* defs.h (enum language): Add language_java.
authorPer Bothner <per@bothner.com>
Fri, 18 Apr 1997 02:22:18 +0000 (02:22 +0000)
committerPer Bothner <per@bothner.com>
Fri, 18 Apr 1997 02:22:18 +0000 (02:22 +0000)
* java-exp.y, java-lang.c, java-lang.h, java-valprint.c:  New files.
* Makefile.in:  Upadte for new files.
* objfiles.c (allocate_objfile):  Allow NULL bfd argument.
* symfile.c (deduce_language_from_filename):  Recognize .java.

gdb/ChangeLog
gdb/Makefile.in
gdb/defs.h
gdb/java-exp.y [new file with mode: 0644]
gdb/java-lang.c [new file with mode: 0644]
gdb/java-lang.h [new file with mode: 0644]
gdb/java-valprint.c [new file with mode: 0644]
gdb/objfiles.c

index b57241f77fe424148856c6c6d1f047ddd7e6a173..adaf46a5364fbc4a2a6cd8eb739c743e42fae48f 100644 (file)
@@ -1,3 +1,11 @@
+Thu Apr 17 14:30:04 1997  Per Bothner  <bothner@deneb.cygnus.com>
+
+       * defs.h (enum language):  Add language_java.
+       * java-exp.y, java-lang.c, java-lang.h, java-valprint.c:  New files.
+       * Makefile.in:  Upadte for new files.
+       * objfiles.c (allocate_objfile):  Allow NULL bfd argument.
+       * symfile.c (deduce_language_from_filename):  Recognize .java.
+
 Thu Apr 17 02:20:23 1997  Doug Evans  <dje@canuck.cygnus.com>
 
        * m32r-stub.c (stash_registers): Rewrite.
index 9e86d0af5fbde59654dffd81bb1ae928e631df5e..fe3633e5144c1b06f4817070da7b83ace7dfdd88 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996
+# Copyright 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997
 # Free Software Foundation, Inc.
 
 # This file is part of GDB.
@@ -357,6 +357,7 @@ SFILES = bcache.c blockframe.c breakpoint.c buildsym.c c-exp.y \
        elfread.c environ.c eval.c expprint.c \
        f-exp.y f-lang.c f-typeprint.c f-valprint.c findvar.c \
        gdbtypes.c infcmd.c inflow.c infrun.c language.c \
+       java-exp.y java-lang.c java-valprint.c \
        m2-exp.y m2-lang.c m2-typeprint.c m2-valprint.c main.c maint.c \
        mem-break.c minsyms.c mipsread.c nlmread.c objfiles.c parse.c \
        printcmd.c remote.c remote-nrom.c scm-exp.c scm-lang.c scm-valprint.c \
@@ -383,6 +384,7 @@ remote-sim_h =      $(INCLUDE_DIR)/remote-sim.h
 dcache_h = dcache.h
 remote_utils_h = $(dcache_h) serial.h target.h remote-utils.h $(remote-sim_h)
 
+
 readline_headers = \
        $(READLINE_SRC)/chardefs.h \
        $(READLINE_SRC)/history.h \
@@ -425,7 +427,7 @@ HFILES_NO_SRCDIR = bcache.h buildsym.h call-cmds.h coff-solib.h defs.h \
        gdb-stabs.h $(inferior_h) language.h minimon.h monitor.h \
        objfiles.h parser-defs.h partial-stab.h serial.h signals.h solib.h \
        symfile.h stabsread.h target.h terminal.h typeprint.h xcoffsolib.h \
-       c-lang.h ch-lang.h f-lang.h m2-lang.h \
+       c-lang.h ch-lang.h f-lang.h java-lang.h m2-lang.h \
        complaints.h valprint.h \
        29k-share/udi/udiids.h 29k-share/udi_soc nindy-share/b.out.h \
        nindy-share/block_io.h nindy-share/coff.h \
@@ -471,7 +473,8 @@ COMMON_OBS = version.o blockframe.o breakpoint.o findvar.o stack.o thread.o \
        exec.o bcache.o objfiles.o minsyms.o maint.o demangle.o \
        dbxread.o coffread.o elfread.o \
        dwarfread.o dwarf2read.o mipsread.o stabsread.o corefile.o \
-       c-lang.o ch-exp.o ch-lang.o f-lang.o m2-lang.o \
+       c-lang.o ch-exp.o ch-lang.o f-lang.o \
+       java-lang.o java-valprint.o m2-lang.o \
        scm-exp.o scm-lang.o scm-valprint.o complaints.o typeprint.o \
        c-typeprint.o ch-typeprint.o f-typeprint.o m2-typeprint.o \
        c-valprint.o cp-valprint.o ch-valprint.o f-valprint.o m2-valprint.o \
@@ -490,8 +493,8 @@ NTSSTART = kdb-start.o
 SUBDIRS = doc testsuite nlm
 
 # For now, shortcut the "configure GDB for fewer languages" stuff.
-YYFILES = c-exp.tab.c f-exp.tab.c m2-exp.tab.c
-YYOBJ = c-exp.tab.o f-exp.tab.o m2-exp.tab.o
+YYFILES = c-exp.tab.c java-exp.tab.c f-exp.tab.c m2-exp.tab.c
+YYOBJ = c-exp.tab.o java-exp.tab.o f-exp.tab.o m2-exp.tab.o
 
 # Things which need to be built when making a distribution.
 
@@ -543,7 +546,14 @@ install-only:
                $(INSTALL_DATA) $(srcdir)/gdb.1 $(man1dir)/$$transformed_name.1
        # start-sanitize-gdbtk
        if [ x"$(ENABLE_GDBTK)" != x ] ; then \
-                 $(INSTALL_DATA) $(srcdir)/gdbtk.tcl $(datadir)/gdbtk.tcl ; \
+                 echo "Making directory gdbtcl"; \
+                 mkdir $(datadir)/gdbtcl; \
+                 chmod 755 $(datadir)/gdbtcl; \
+                 cd $(srcdir)/gdbtcl ; \
+                       for i in * ; \
+                   do \
+                     $(INSTALL_DATA) $$i $(datadir)/gdbtcl/$$i ; \
+                   done ; \
                else \
                  true ; \
                fi
@@ -559,11 +569,6 @@ uninstall: force
                  true ; \
                fi ; \
                rm -f $(bindir)/$$transformed_name $(man1dir)/$$transformed_name.1
-       # start-sanitize-gdbtk
-       if [ x"$(ENABLE_GDBTK)" != x ] ; then \
-               rm -f $(datadir)/gdbtk.tcl ; \
-       fi
-       # end-sanitize-gdbtk
        @$(MAKE) DO=uninstall "DODIRS=$(SUBDIRS)" $(FLAGS_TO_PASS) subdir_do 
 
 # We do this by grepping through sources.  If that turns out to be too slow,
@@ -635,10 +640,10 @@ libgdb-files: $(LIBGDBDEPS) Makefile.in
 saber_gdb: $(SFILES) $(DEPFILES) copying.c version.c
        #setopt load_flags $(CFLAGS) $(BFD_CFLAGS) -DHOST_SYS=SUN4_SYS
        #load ./init.c $(SFILES)
-       #unload $(srcdir)/c-exp.y $(srcdir)/m2-exp.y
+       #unload $(srcdir)/c-exp.y $(srcdir)/java-exp.y $(srcdir)/m2-exp.y
        #unload vx-share/*.h
        #unload nindy-share/[A-Z]*
-       #load c-exp.tab.c m2-exp.tab.c
+       #load c-exp.tab.c java-exp.tab.c m2-exp.tab.c
        #load copying.c version.c
        #load ../opcodes/libopcodes.a
        #load ../libiberty/libiberty.a
@@ -733,7 +738,7 @@ clean mostlyclean:
 # functionality described is if the distributed files are unmodified.
 distclean: clean
        @$(MAKE) $(FLAGS_TO_PASS) DO=distclean "DODIRS=$(SUBDIRS)" subdir_do 
-       rm -f nm.h tm.h xm.h config.status config.h stamp-h
+       rm -f nm.h tm.h xm.h config.status config.h stamp-h .gdbinit
        rm -f y.output yacc.acts yacc.tmp y.tab.h
        rm -f config.log config.cache
        rm -f Makefile
@@ -742,7 +747,7 @@ maintainer-clean realclean: clean
        @echo "This command is intended for maintainers to use;"
        @echo "it deletes files that may require special tools to rebuild."
        @$(MAKE) $(FLAGS_TO_PASS) DO=maintainer-clean "DODIRS=$(SUBDIRS)" subdir_do
-       rm -f c-exp.tab.c f-exp.tab.c m2-exp.tab.c
+       rm -f c-exp.tab.c java-exp.tab.c f-exp.tab.c m2-exp.tab.c
        rm -f TAGS $(INFOFILES)
        rm -f nm.h tm.h xm.h config.status
        rm -f y.output yacc.acts yacc.tmp
@@ -821,6 +826,19 @@ c-exp.tab.c: c-exp.y
        -rm y.tab.c
        mv c-exp.new ./c-exp.tab.c
 
+java-exp.tab.o: java-exp.tab.c
+java-exp.tab.c: java-exp.y
+       $(YACC) $(YFLAGS) $(srcdir)/java-exp.y
+       -sed -e '/extern.*malloc/d' \
+            -e '/extern.*realloc/d' \
+            -e '/extern.*free/d' \
+            -e '/include.*malloc.h/d' \
+            -e 's/malloc/xmalloc/g' \
+            -e 's/realloc/xrealloc/g' \
+         < y.tab.c > java-exp.new
+       -rm y.tab.c
+       mv java-exp.new ./java-exp.tab.c
+
 f-exp.tab.o: f-exp.tab.c
 f-exp.tab.c: f-exp.y c-exp.tab.c
        $(YACC) $(YFLAGS) $(srcdir)/f-exp.y
@@ -852,7 +870,7 @@ m2-exp.tab.c: m2-exp.y
        mv m2-exp.new ./m2-exp.tab.c
 
 # These files are updated atomically, so make never has to remove them
-.PRECIOUS: m2-exp.tab.c f-exp.tab.c c-exp.tab.c
+.PRECIOUS: m2-exp.tab.c java-exp.tab.c f-exp.tab.c c-exp.tab.c
 
 lint: $(LINTFILES)
        $(LINT) $(INCLUDE_CFLAGS) $(LINTFLAGS) $(LINTFILES) \
@@ -1140,7 +1158,7 @@ fork-child.o: fork-child.c $(wait_h) $(defs_h) $(gdbcore_h) \
 gdbtk.o: gdbtk.c $(defs_h) $(symtab_h) $(inferior_h) $(command_h) \
        $(bfd_h) symfile.h objfiles.h target.h gdb_string.h
        $(CC) -c $(INTERNAL_CFLAGS) $(TCL_CFLAGS) $(TK_CFLAGS) $(X11_CFLAGS) \
-               $(srcdir)/gdbtk.c -DGDBTK_FILENAME=\"$(datadir)/gdbtk.tcl\"
+               $(srcdir)/gdbtk.c -DGDBTK_LIBRARY=\"$(datadir)/gdbtcl\"
 # end-sanitize-gdbtk
 
 gdbtypes.o: gdbtypes.c $(bfd_h) complaints.h $(defs_h) $(expression_h) \
@@ -1506,6 +1524,10 @@ symtab.o: symtab.c call-cmds.h $(defs_h) $(expression_h) $(frame_h) \
 tahoe-tdep.o: tahoe-tdep.c $(OP_INCLUDE)/tahoe.h $(defs_h) \
        $(symtab_h)
 
+#start-sanitize-tic80
+tic80-tdep.o: tic80-tdep.c $(defs_h)
+#end-sanitize-tic80
+
 target.o: target.c $(bfd_h) $(defs_h) $(gdbcmd_h) $(inferior_h) \
        objfiles.h symfile.h target.h gdb_string.h
 
@@ -1576,6 +1598,10 @@ c-exp.tab.o: c-exp.tab.c c-lang.h $(defs_h) $(expression_h) \
        $(gdbtypes_h) language.h parser-defs.h $(symtab_h) $(value_h) \
        $(bfd_h) objfiles.h symfile.h
 
+java-exp.tab.o: java-exp.tab.c java-lang.h $(defs_h) $(expression_h) \
+       $(gdbtypes_h) language.h parser-defs.h $(symtab_h) $(value_h) \
+       $(bfd_h) objfiles.h symfile.h
+
 f-exp.tab.o: f-exp.tab.c f-lang.h $(defs_h) $(expression_h) \
        language.h parser-defs.h $(value_h) $(bfd_h) objfiles.h symfile.h
 
index b8bb15e001c20d483ce3b117ea9d061a2861330e..e170b71fdcda399d19afce81eb50b8e8aa41b698 100644 (file)
@@ -134,6 +134,7 @@ enum language
    language_auto,              /* Placeholder for automatic setting */
    language_c,                         /* C */
    language_cplus,             /* C++ */
+   language_java,              /* Java */
    language_chill,             /* Chill */
    language_fortran,           /* Fortran */
    language_m2,                        /* Modula-2 */
@@ -231,11 +232,11 @@ extern void request_quit PARAMS ((int));
 
 extern void do_cleanups PARAMS ((struct cleanup *));
 extern void do_final_cleanups PARAMS ((struct cleanup *));
-extern void do_my_cleanups PARAMS ((struct cleanup *, struct cleanup *));
+extern void do_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));
 
 extern void discard_cleanups PARAMS ((struct cleanup *));
 extern void discard_final_cleanups PARAMS ((struct cleanup *));
-extern void discard_my_cleanups PARAMS ((struct cleanup *, struct cleanup *));
+extern void discard_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));
 
 /* The bare make_cleanup function is one of those rare beasts that
    takes almost any type of function as the first arg and anything that
@@ -254,15 +255,15 @@ extern struct cleanup *make_cleanup ();
 extern struct cleanup *
 make_final_cleanup PARAMS ((void (*function) (void *), void *));
 extern struct cleanup *
-make_my_cleanup PARAMS ((struct cleanup *, void (*function) (void *), void *));
+make_my_cleanup PARAMS ((struct cleanup **, void (*function) (void *), void *));
 
 extern struct cleanup *save_cleanups PARAMS ((void));
 extern struct cleanup *save_final_cleanups PARAMS ((void));
-extern struct cleanup *save_my_cleanups PARAMS ((struct cleanup *));
+extern struct cleanup *save_my_cleanups PARAMS ((struct cleanup **));
 
 extern void restore_cleanups PARAMS ((struct cleanup *));
 extern void restore_final_cleanups PARAMS ((struct cleanup *));
-extern void restore_my_cleanups PARAMS ((struct cleanup *, struct cleanup *));
+extern void restore_my_cleanups PARAMS ((struct cleanup **, struct cleanup *));
 
 extern void free_current_contents PARAMS ((char **));
 
@@ -549,6 +550,8 @@ enum val_prettyprint
 #define        LONG_MAX ((long)(ULONG_MAX >> 1))       /* 0x7FFFFFFF for 32-bits */
 #endif
 
+#ifndef LONGEST
+
 #ifdef BFD64
 
 /* This is to make sure that LONGEST is at least as big as CORE_ADDR.  */
@@ -558,18 +561,25 @@ enum val_prettyprint
 
 #else /* No BFD64 */
 
-#ifndef LONGEST
 #  ifdef CC_HAS_LONG_LONG
 #    define LONGEST long long
 #    define ULONGEST unsigned long long
 #  else
-#    define LONGEST long
-#    define ULONGEST unsigned long
+/* BFD_HOST_64_BIT is defined for some hosts that don't have long long
+   (e.g. i386-windows) so try it.  */
+#    ifdef BFD_HOST_64_BIT
+#      define LONGEST BFD_HOST_64_BIT
+#      define ULONGEST BFD_HOST_U_64_BIT
+#    else
+#      define LONGEST long
+#      define ULONGEST unsigned long
+#    endif
 #  endif
-#endif
 
 #endif /* No BFD64 */
 
+#endif /* ! LONGEST */
+
 /* Convert a LONGEST to an int.  This is used in contexts (e.g. number of
    arguments to a function, number in a value history, register number, etc.)
    where the value must not be larger than can fit in an int.  */
diff --git a/gdb/java-exp.y b/gdb/java-exp.y
new file mode 100644 (file)
index 0000000..3d810a9
--- /dev/null
@@ -0,0 +1,1228 @@
+/* YACC parser for Java expressions, for GDB.
+   Copyright (C) 1997.
+   Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program 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 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+/* Parse a C expression from text in a string,
+   and return the result as a  struct expression  pointer.
+   That structure contains arithmetic operations in reverse polish,
+   with constants represented by operations that are followed by special data.
+   See expression.h for the details of the format.
+   What is important here is that it can be built up sequentially
+   during the process of parsing; the lower levels of the tree always
+   come first in the result.
+
+   Note that malloc's and realloc's in this file are transformed to
+   xmalloc and xrealloc respectively by the same sed command in the
+   makefile that remaps any other malloc/realloc inserted by the parser
+   generator.  Doing this with #defines and trying to control the interaction
+   with include files (<malloc.h> and <stdlib.h> for example) just became
+   too messy, particularly when such includes can be inserted at random
+   times by the parser generator.  */
+  
+%{
+
+#include "defs.h"
+#include "gdb_string.h"
+#include <ctype.h>
+#include "expression.h"
+#include "value.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "java-lang.h"
+#include "bfd.h" /* Required by objfiles.h.  */
+#include "symfile.h" /* Required by objfiles.h.  */
+#include "objfiles.h" /* For have_full_symbols and have_partial_symbols */
+
+/* Remap normal yacc parser interface names (yyparse, yylex, yyerror, etc),
+   as well as gratuitiously global symbol names, so we can have multiple
+   yacc generated parsers in gdb.  Note that these are only the variables
+   produced by yacc.  If other parser generators (bison, byacc, etc) produce
+   additional global names that conflict at link time, then those parser
+   generators need to be fixed instead of adding those names to this list. */
+
+#define        yymaxdepth java_maxdepth
+#define        yyparse java_parse
+#define        yylex   java_lex
+#define        yyerror java_error
+#define        yylval  java_lval
+#define        yychar  java_char
+#define        yydebug java_debug
+#define        yypact  java_pact       
+#define        yyr1    java_r1                 
+#define        yyr2    java_r2                 
+#define        yydef   java_def                
+#define        yychk   java_chk                
+#define        yypgo   java_pgo                
+#define        yyact   java_act                
+#define        yyexca  java_exca
+#define yyerrflag java_errflag
+#define yynerrs        java_nerrs
+#define        yyps    java_ps
+#define        yypv    java_pv
+#define        yys     java_s
+#define        yy_yys  java_yys
+#define        yystate java_state
+#define        yytmp   java_tmp
+#define        yyv     java_v
+#define        yy_yyv  java_yyv
+#define        yyval   java_val
+#define        yylloc  java_lloc
+#define yyreds java_reds               /* With YYDEBUG defined */
+#define yytoks java_toks               /* With YYDEBUG defined */
+#define yylhs  java_yylhs
+#define yylen  java_yylen
+#define yydefred java_yydefred
+#define yydgoto        java_yydgoto
+#define yysindex java_yysindex
+#define yyrindex java_yyrindex
+#define yygindex java_yygindex
+#define yytable         java_yytable
+#define yycheck         java_yycheck
+
+#ifndef YYDEBUG
+#define        YYDEBUG 0               /* Default to no yydebug support */
+#endif
+
+int
+yyparse PARAMS ((void));
+
+static int
+yylex PARAMS ((void));
+
+void
+yyerror PARAMS ((char *));
+
+static struct type * java_type_from_name PARAMS ((struct stoken));
+static void push_variable PARAMS ((struct stoken));
+
+%}
+
+/* Although the yacc "value" of an expression is not used,
+   since the result is stored in the structure being created,
+   other node types do have values.  */
+
+%union
+  {
+    LONGEST lval;
+    struct {
+      LONGEST val;
+      struct type *type;
+    } typed_val_int;
+    struct {
+      DOUBLEST dval;
+      struct type *type;
+    } typed_val_float;
+    struct symbol *sym;
+    struct type *tval;
+    struct stoken sval;
+    struct ttype tsym;
+    struct symtoken ssym;
+    struct block *bval;
+    enum exp_opcode opcode;
+    struct internalvar *ivar;
+    int *ivec;
+  }
+
+%{
+/* YYSTYPE gets defined by %union */
+static int
+parse_number PARAMS ((char *, int, int, YYSTYPE *));
+%}
+
+%type <lval> rcurly BooleanLiteral Dims Dims_opt
+%type <tval> ClassOrInterfaceType ClassType /* ReferenceType Type ArrayType */
+%type <tval> IntegralType FloatingPointType NumericType PrimitiveType
+
+%token <typed_val_int> INTEGER_LITERAL
+%token <typed_val_float> FLOATING_POINT_LITERAL
+
+%token <sval> IDENTIFIER
+%token <sval> STRING_LITERAL
+%token <tsym> TYPENAME
+%type <sval> Name SimpleName QualifiedName ForcedName
+
+/* A NAME_OR_INT is a symbol which is not known in the symbol table,
+   but which would parse as a valid number in the current input radix.
+   E.g. "c" when input_radix==16.  Depending on the parse, it will be
+   turned into a name or into a number.  */
+
+%token <sval> NAME_OR_INT 
+
+%token ERROR
+
+/* Special type cases, put in to allow the parser to distinguish different
+   legal basetypes.  */
+%token LONG SHORT BYTE INT CHAR BOOLEAN DOUBLE FLOAT
+
+%token VARIABLE
+
+%token <opcode> ASSIGN_MODIFY
+
+%token THIS SUPER TRUE FALSE NEW
+
+%left ','
+%right '=' ASSIGN_MODIFY
+%right '?'
+%left OROR
+%left ANDAND
+%left '|'
+%left '^'
+%left '&'
+%left EQUAL NOTEQUAL
+%left '<' '>' LEQ GEQ
+%left LSH RSH
+%left '+' '-'
+%left '*' '/' '%'
+%right INCREMENT DECREMENT
+%right '.' '[' '('
+
+\f
+%%
+
+start   :      exp1
+/*     |       type_exp FIXME */
+       ;
+
+StringLiteral:
+       STRING_LITERAL
+               {
+                 write_exp_elt_opcode (OP_STRING);
+                 write_exp_string ($1);
+                 write_exp_elt_opcode (OP_STRING);
+               }
+;
+
+BooleanLiteral:
+       FALSE
+               { $$ = 0; }
+|      TRUE
+               { $$ = 1; }
+;
+
+Literal        :
+       INTEGER_LITERAL
+               { write_exp_elt_opcode (OP_LONG);
+                 write_exp_elt_type ($1.type);
+                 write_exp_elt_longcst ((LONGEST)($1.val));
+                 write_exp_elt_opcode (OP_LONG); }
+|      NAME_OR_INT
+               { YYSTYPE val;
+                 parse_number ($1.ptr, $1.length, 0, &val);
+                 write_exp_elt_opcode (OP_LONG);
+                 write_exp_elt_type (val.typed_val_int.type);
+                 write_exp_elt_longcst ((LONGEST)val.typed_val_int.val);
+                 write_exp_elt_opcode (OP_LONG);
+               }
+|      FLOATING_POINT_LITERAL
+               { write_exp_elt_opcode (OP_DOUBLE);
+                 write_exp_elt_type ($1.type);
+                 write_exp_elt_dblcst ($1.dval);
+                 write_exp_elt_opcode (OP_DOUBLE); }
+|      BooleanLiteral
+               { write_exp_elt_opcode (OP_LONG);
+                 write_exp_elt_type (java_boolean_type);
+                 write_exp_elt_longcst ((LONGEST)$1);
+                 write_exp_elt_opcode (OP_LONG); }
+|      StringLiteral
+       ;
+
+/* UNUSED:
+Type:
+       PrimitiveType
+|      ReferenceType
+;
+*/
+
+PrimitiveType:
+       NumericType
+|      BOOLEAN
+               { $$ = java_boolean_type; }
+;
+
+NumericType:
+       IntegralType
+|      FloatingPointType
+;
+
+IntegralType:
+       BYTE
+               { $$ = java_byte_type; }
+|      SHORT
+               { $$ = java_short_type; }
+|      INT
+               { $$ = java_int_type; }
+|      LONG
+               { $$ = java_long_type; }
+|      CHAR
+               { $$ = java_char_type; }
+;
+
+FloatingPointType:
+       FLOAT
+               { $$ = java_float_type; }
+|      DOUBLE
+               { $$ = java_double_type; }
+;
+
+/* UNUSED:
+ReferenceType:
+       ClassOrInterfaceType
+|      ArrayType
+;
+*/
+
+ClassOrInterfaceType:
+       Name
+               { $$ = java_type_from_name ($1); }
+;
+
+ClassType:
+       ClassOrInterfaceType
+;
+
+/* UNUSED:
+ArrayType:
+       PrimitiveType Dims
+               { $$ = java_array_type ($1, $2); }
+|      Name Dims
+               { $$ = java_array_type (java_type_from_name ($1), $2); }
+;
+*/
+
+Name:
+       IDENTIFIER
+|      QualifiedName
+;
+
+ForcedName:
+       SimpleName
+|      QualifiedName
+;
+
+SimpleName:
+       IDENTIFIER
+|      NAME_OR_INT
+;
+
+QualifiedName:
+       Name '.' SimpleName
+               { $$.length = $1.length + $3.length + 1;
+                 if ($1.ptr + $1.length + 1 == $3.ptr
+                     && $1.ptr[$1.length] == '.')
+                   $$.ptr = $1.ptr;  /* Optimization. */
+                 else
+                   {
+                     $$.ptr = (char *) malloc ($$.length + 1);
+                     make_cleanup (free, $$.ptr);
+                     sprintf ($$.ptr, "%.*s.%.*s",
+                              $1.length, $1.ptr, $3.length, $3.ptr);
+               } }
+;
+
+/*
+type_exp:      type
+                       { write_exp_elt_opcode(OP_TYPE);
+                         write_exp_elt_type($1);
+                         write_exp_elt_opcode(OP_TYPE);}
+       ;
+       */
+
+/* Expressions, including the comma operator.  */
+exp1   :       Expression
+       |       exp1 ',' Expression
+                       { write_exp_elt_opcode (BINOP_COMMA); }
+       ;
+
+Primary:
+       PrimaryNoNewArray
+|      ArrayCreationExpression
+;
+
+PrimaryNoNewArray:
+       Literal
+|      THIS
+               { write_exp_elt_opcode (OP_THIS);
+                 write_exp_elt_opcode (OP_THIS); }
+|      '(' Expression ')'
+|      ClassInstanceCreationExpression
+|      FieldAccess
+|      MethodInvocation
+|      ArrayAccess
+|      lcurly ArgumentList rcurly
+               { write_exp_elt_opcode (OP_ARRAY);
+                 write_exp_elt_longcst ((LONGEST) 0);
+                 write_exp_elt_longcst ((LONGEST) $3);
+                 write_exp_elt_opcode (OP_ARRAY); }
+;
+
+lcurly:
+       '{'
+               { start_arglist (); }
+;
+
+rcurly:
+       '}'
+               { $$ = end_arglist () - 1; }
+;
+
+ClassInstanceCreationExpression:
+       NEW ClassType '(' ArgumentList_opt ')'
+               { error ("FIXME - ClassInstanceCreationExpression"); }
+;
+
+ArgumentList:
+       Expression
+               { arglist_len = 1; }
+|      ArgumentList ',' Expression
+               { arglist_len++; }
+;
+
+ArgumentList_opt:
+       /* EMPTY */
+               { arglist_len = 0; }
+| ArgumentList
+;
+
+ArrayCreationExpression:
+       NEW PrimitiveType DimExprs Dims_opt
+               { error ("FIXME - ArrayCreatiionExpression"); }
+|      NEW ClassOrInterfaceType DimExprs Dims_opt
+               { error ("FIXME - ArrayCreatiionExpression"); }
+;
+
+DimExprs:
+       DimExpr
+|      DimExprs DimExpr
+;
+
+DimExpr:
+       '[' Expression ']'
+;
+
+Dims:
+       '[' ']'
+               { $$ = 1; }
+|      Dims '[' ']'
+       { $$ = $1 + 1; }
+;
+
+Dims_opt:
+       Dims
+|      /* EMPTY */
+               { $$ = 0; }
+;
+
+FieldAccess:
+       Primary '.' SimpleName
+               { write_exp_elt_opcode (STRUCTOP_STRUCT);
+                 write_exp_string ($3);
+                 write_exp_elt_opcode (STRUCTOP_STRUCT); }
+/*|    SUPER '.' SimpleName { FIXME } */
+;
+
+MethodInvocation:
+       Name '(' ArgumentList_opt ')'
+               { error ("method invocation not implemented"); }
+|      Primary '.' SimpleName '(' ArgumentList_opt ')'
+               { error ("method invocation not implemented"); }
+|      SUPER '.' SimpleName '(' ArgumentList_opt ')'
+               { error ("method invocation not implemented"); }
+;
+
+ArrayAccess:
+       Name '[' Expression ']'
+               { error ("ArrayAccess"); } /* FIXME - NASTY */
+|      PrimaryNoNewArray '[' Expression ']'
+               { write_exp_elt_opcode (BINOP_SUBSCRIPT); }
+;
+
+PostfixExpression:
+       Primary
+|      Name
+               { push_variable ($1); }
+|      VARIABLE
+               /* Already written by write_dollar_variable. */
+|      PostIncrementExpression
+|      PostDecrementExpression
+;
+
+PostIncrementExpression:
+       PostfixExpression INCREMENT
+               { write_exp_elt_opcode (UNOP_POSTINCREMENT); }
+;
+
+PostDecrementExpression:
+       PostfixExpression DECREMENT
+               { write_exp_elt_opcode (UNOP_POSTDECREMENT); }
+;
+
+UnaryExpression:
+       PreIncrementExpression
+|      PreDecrementExpression
+|      '+' UnaryExpression
+|      '-' UnaryExpression
+               { write_exp_elt_opcode (UNOP_NEG); }
+|      '*' UnaryExpression 
+               { write_exp_elt_opcode (UNOP_IND); } /*FIXME not in Java  */
+|      UnaryExpressionNotPlusMinus
+;
+
+PreIncrementExpression:
+       INCREMENT UnaryExpression
+               { write_exp_elt_opcode (UNOP_PREINCREMENT); }
+;
+
+PreDecrementExpression:
+       DECREMENT UnaryExpression
+               { write_exp_elt_opcode (UNOP_PREDECREMENT); }
+;
+
+UnaryExpressionNotPlusMinus:
+       PostfixExpression
+|      '~' UnaryExpression
+               { write_exp_elt_opcode (UNOP_COMPLEMENT); }
+|      '!' UnaryExpression
+               { write_exp_elt_opcode (UNOP_LOGICAL_NOT); }
+|      CastExpression
+       ;
+
+CastExpression:
+       '(' PrimitiveType Dims_opt ')' UnaryExpression
+               { write_exp_elt_opcode (UNOP_CAST);
+                 write_exp_elt_type (java_array_type ($2, $3));
+                 write_exp_elt_opcode (UNOP_CAST); }
+|      '(' Expression ')' UnaryExpressionNotPlusMinus /* FIXME */
+|      '(' Name Dims ')' UnaryExpressionNotPlusMinus
+               { write_exp_elt_opcode (UNOP_CAST);
+                 write_exp_elt_type (java_array_type (java_type_from_name ($2), $3));
+                 write_exp_elt_opcode (UNOP_CAST); }
+;
+
+
+MultiplicativeExpression:
+       UnaryExpression
+|      MultiplicativeExpression '*' UnaryExpression
+               { write_exp_elt_opcode (BINOP_MUL); }
+|      MultiplicativeExpression '/' UnaryExpression
+               { write_exp_elt_opcode (BINOP_DIV); }
+|      MultiplicativeExpression '%' UnaryExpression
+               { write_exp_elt_opcode (BINOP_REM); }
+;
+
+AdditiveExpression:
+       MultiplicativeExpression
+|      AdditiveExpression '+' MultiplicativeExpression
+               { write_exp_elt_opcode (BINOP_ADD); }
+|      AdditiveExpression '-' MultiplicativeExpression
+               { write_exp_elt_opcode (BINOP_SUB); }
+;
+
+ShiftExpression:
+       AdditiveExpression
+|      ShiftExpression LSH AdditiveExpression
+               { write_exp_elt_opcode (BINOP_LSH); }
+|      ShiftExpression RSH AdditiveExpression
+               { write_exp_elt_opcode (BINOP_RSH); }
+/* |   ShiftExpression >>> AdditiveExpression { FIXME } */
+;
+
+RelationalExpression:
+       ShiftExpression
+|      RelationalExpression '<' ShiftExpression
+               { write_exp_elt_opcode (BINOP_LESS); }
+|      RelationalExpression '>' ShiftExpression
+               { write_exp_elt_opcode (BINOP_GTR); }
+|      RelationalExpression LEQ ShiftExpression
+               { write_exp_elt_opcode (BINOP_LEQ); }
+|      RelationalExpression GEQ ShiftExpression
+               { write_exp_elt_opcode (BINOP_GEQ); }
+/* | RelationalExpresion INSTANCEOF ReferenceType { FIXME } */
+;
+
+EqualityExpression:
+       RelationalExpression
+|      EqualityExpression EQUAL RelationalExpression
+               { write_exp_elt_opcode (BINOP_EQUAL); }
+|      EqualityExpression NOTEQUAL RelationalExpression
+               { write_exp_elt_opcode (BINOP_NOTEQUAL); }
+;
+
+AndExpression:
+       EqualityExpression
+|      AndExpression '&' EqualityExpression
+               { write_exp_elt_opcode (BINOP_BITWISE_AND); }
+;
+
+ExclusiveOrExpression:
+       AndExpression
+|      ExclusiveOrExpression '^' AndExpression
+               { write_exp_elt_opcode (BINOP_BITWISE_XOR); }
+;
+InclusiveOrExpression:
+       ExclusiveOrExpression
+|      InclusiveOrExpression '|' ExclusiveOrExpression
+               { write_exp_elt_opcode (BINOP_BITWISE_IOR); }
+;
+
+ConditionalAndExpression:
+       InclusiveOrExpression
+|      ConditionalAndExpression ANDAND InclusiveOrExpression
+               { write_exp_elt_opcode (BINOP_LOGICAL_AND); }
+;
+
+ConditionalOrExpression:
+       ConditionalAndExpression
+|      ConditionalOrExpression OROR ConditionalAndExpression
+               { write_exp_elt_opcode (BINOP_LOGICAL_OR); }
+;
+
+ConditionalExpression:
+       ConditionalOrExpression
+|      ConditionalOrExpression '?' Expression ':' ConditionalExpression
+               { write_exp_elt_opcode (TERNOP_COND); }
+;
+
+AssignmentExpression:
+       ConditionalExpression
+|      Assignment
+;
+                         
+Assignment:
+       LeftHandSide '=' ConditionalExpression
+               { write_exp_elt_opcode (BINOP_ASSIGN); }
+|      LeftHandSide ASSIGN_MODIFY ConditionalExpression
+               { write_exp_elt_opcode (BINOP_ASSIGN_MODIFY);
+                 write_exp_elt_opcode ($2);
+                 write_exp_elt_opcode (BINOP_ASSIGN_MODIFY); }
+;
+
+LeftHandSide:
+       ForcedName
+               { push_variable ($1); }
+|      VARIABLE
+               /* Already written by write_dollar_variable. */
+|      FieldAccess
+|      ArrayAccess
+;
+
+
+Expression:
+       AssignmentExpression
+;
+
+%%
+/* Take care of parsing a number (anything that starts with a digit).
+   Set yylval and return the token type; update lexptr.
+   LEN is the number of characters in it.  */
+
+/*** Needs some error checking for the float case ***/
+
+static int
+parse_number (p, len, parsed_float, putithere)
+     register char *p;
+     register int len;
+     int parsed_float;
+     YYSTYPE *putithere;
+{
+  register ULONGEST n = 0;
+  ULONGEST limit, limit_div_base;
+
+  register int c;
+  register int base = input_radix;
+  int unsigned_p = 0;
+
+  struct type *type;
+
+  if (parsed_float)
+    {
+      /* It's a float since it contains a point or an exponent.  */
+
+      if (sizeof (putithere->typed_val_float.dval) <= sizeof (float))
+       sscanf (p, "%g", &putithere->typed_val_float.dval);
+      else if (sizeof (putithere->typed_val_float.dval) <= sizeof (double))
+       sscanf (p, "%lg", &putithere->typed_val_float.dval);
+      else
+       {
+#ifdef PRINTF_HAS_LONG_DOUBLE
+         sscanf (p, "%Lg", &putithere->typed_val_float.dval);
+#else
+         /* Scan it into a double, then assign it to the long double.
+            This at least wins with values representable in the range
+            of doubles. */
+         double temp;
+         sscanf (p, "%lg", &temp);
+         putithere->typed_val_float.dval = temp;
+#endif
+       }
+
+      /* See if it has `f' or `d' suffix (float or double).  */
+
+      c = tolower (p[len - 1]);
+
+      if (c == 'f' || c == 'F')
+       putithere->typed_val_float.type = builtin_type_float;
+      else if (isdigit (c) || c == '.' || c == 'd' || c == 'D')
+       putithere->typed_val_float.type = builtin_type_double;
+      else
+       return ERROR;
+
+      return FLOATING_POINT_LITERAL;
+}
+
+  /* Handle base-switching prefixes 0x, 0t, 0d, 0 */
+  if (p[0] == '0')
+    switch (p[1])
+      {
+      case 'x':
+      case 'X':
+       if (len >= 3)
+         {
+           p += 2;
+           base = 16;
+           len -= 2;
+         }
+       break;
+
+      case 't':
+      case 'T':
+      case 'd':
+      case 'D':
+       if (len >= 3)
+         {
+           p += 2;
+           base = 10;
+           len -= 2;
+         }
+       break;
+
+      default:
+       base = 8;
+       break;
+      }
+
+  c = p[len-1];
+  limit = (ULONGEST)0xffffffff;
+  if (c == 'l' || c == 'L')
+    {
+      type = java_long_type;
+      len--;
+      /* A paranoid calculation of (1<<64)-1. */
+      limit = ((limit << 16) << 16) | limit;
+    }
+  else
+    {
+      type = java_int_type;
+    }
+  limit_div_base = limit / (ULONGEST) base;
+
+  while (--len >= 0)
+    {
+      c = *p++;
+      if (c >= '0' && c <= '9')
+       c -= '0';
+      else
+       {
+         if (c >= 'A' && c <= 'Z')
+           c += 'a' - 'A';
+         if (c >= 'a' && c - 'a' + 10 < base)
+           c -= 'a' + 10;
+         else
+           return ERROR;       /* Char not a digit */
+       }
+      if (c >= base)
+       return ERROR;
+      if (n > limit_div_base
+         || (n *= base) > limit - c)
+       error ("Numeric constant too large.");
+      n += c;
+       }
+
+   putithere->typed_val_int.val = n;
+   putithere->typed_val_int.type = type;
+   return INTEGER_LITERAL;
+}
+
+struct token
+{
+  char *operator;
+  int token;
+  enum exp_opcode opcode;
+};
+
+static const struct token tokentab3[] =
+  {
+    {">>=", ASSIGN_MODIFY, BINOP_RSH},
+    {"<<=", ASSIGN_MODIFY, BINOP_LSH}
+  };
+
+static const struct token tokentab2[] =
+  {
+    {"+=", ASSIGN_MODIFY, BINOP_ADD},
+    {"-=", ASSIGN_MODIFY, BINOP_SUB},
+    {"*=", ASSIGN_MODIFY, BINOP_MUL},
+    {"/=", ASSIGN_MODIFY, BINOP_DIV},
+    {"%=", ASSIGN_MODIFY, BINOP_REM},
+    {"|=", ASSIGN_MODIFY, BINOP_BITWISE_IOR},
+    {"&=", ASSIGN_MODIFY, BINOP_BITWISE_AND},
+    {"^=", ASSIGN_MODIFY, BINOP_BITWISE_XOR},
+    {"++", INCREMENT, BINOP_END},
+    {"--", DECREMENT, BINOP_END},
+    {"&&", ANDAND, BINOP_END},
+    {"||", OROR, BINOP_END},
+    {"<<", LSH, BINOP_END},
+    {">>", RSH, BINOP_END},
+    {"==", EQUAL, BINOP_END},
+    {"!=", NOTEQUAL, BINOP_END},
+    {"<=", LEQ, BINOP_END},
+    {">=", GEQ, BINOP_END}
+  };
+
+/* Read one token, getting characters through lexptr.  */
+
+static int
+yylex ()
+{
+  int c;
+  int namelen;
+  unsigned int i;
+  char *tokstart;
+  char *tokptr;
+  int tempbufindex;
+  static char *tempbuf;
+  static int tempbufsize;
+  
+ retry:
+
+  tokstart = lexptr;
+  /* See if it is a special token of length 3.  */
+  for (i = 0; i < sizeof tokentab3 / sizeof tokentab3[0]; i++)
+    if (STREQN (tokstart, tokentab3[i].operator, 3))
+      {
+       lexptr += 3;
+       yylval.opcode = tokentab3[i].opcode;
+       return tokentab3[i].token;
+      }
+
+  /* See if it is a special token of length 2.  */
+  for (i = 0; i < sizeof tokentab2 / sizeof tokentab2[0]; i++)
+    if (STREQN (tokstart, tokentab2[i].operator, 2))
+      {
+       lexptr += 2;
+       yylval.opcode = tokentab2[i].opcode;
+       return tokentab2[i].token;
+      }
+
+  switch (c = *tokstart)
+    {
+    case 0:
+      return 0;
+
+    case ' ':
+    case '\t':
+    case '\n':
+      lexptr++;
+      goto retry;
+
+    case '\'':
+      /* We either have a character constant ('0' or '\177' for example)
+        or we have a quoted symbol reference ('foo(int,int)' in C++
+        for example). */
+      lexptr++;
+      c = *lexptr++;
+      if (c == '\\')
+       c = parse_escape (&lexptr);
+      else if (c == '\'')
+       error ("Empty character constant.");
+
+      yylval.typed_val_int.val = c;
+      yylval.typed_val_int.type = builtin_type_char;
+
+      c = *lexptr++;
+      if (c != '\'')
+       {
+         namelen = skip_quoted (tokstart) - tokstart;
+         if (namelen > 2)
+           {
+             lexptr = tokstart + namelen;
+             if (lexptr[-1] != '\'')
+               error ("Unmatched single quote.");
+             namelen -= 2;
+             tokstart++;
+             goto tryname;
+           }
+         error ("Invalid character constant.");
+       }
+      return INTEGER_LITERAL;
+
+    case '(':
+      paren_depth++;
+      lexptr++;
+      return c;
+
+    case ')':
+      if (paren_depth == 0)
+       return 0;
+      paren_depth--;
+      lexptr++;
+      return c;
+
+    case ',':
+      if (comma_terminates && paren_depth == 0)
+       return 0;
+      lexptr++;
+      return c;
+
+    case '.':
+      /* Might be a floating point number.  */
+      if (lexptr[1] < '0' || lexptr[1] > '9')
+       goto symbol;            /* Nope, must be a symbol. */
+      /* FALL THRU into number case.  */
+
+    case '0':
+    case '1':
+    case '2':
+    case '3':
+    case '4':
+    case '5':
+    case '6':
+    case '7':
+    case '8':
+    case '9':
+      {
+       /* It's a number.  */
+       int got_dot = 0, got_e = 0, toktype;
+       register char *p = tokstart;
+       int hex = input_radix > 10;
+
+       if (c == '0' && (p[1] == 'x' || p[1] == 'X'))
+         {
+           p += 2;
+           hex = 1;
+         }
+       else if (c == '0' && (p[1]=='t' || p[1]=='T' || p[1]=='d' || p[1]=='D'))
+         {
+           p += 2;
+           hex = 0;
+         }
+
+       for (;; ++p)
+         {
+           /* This test includes !hex because 'e' is a valid hex digit
+              and thus does not indicate a floating point number when
+              the radix is hex.  */
+           if (!hex && !got_e && (*p == 'e' || *p == 'E'))
+             got_dot = got_e = 1;
+           /* This test does not include !hex, because a '.' always indicates
+              a decimal floating point number regardless of the radix.  */
+           else if (!got_dot && *p == '.')
+             got_dot = 1;
+           else if (got_e && (p[-1] == 'e' || p[-1] == 'E')
+                    && (*p == '-' || *p == '+'))
+             /* This is the sign of the exponent, not the end of the
+                number.  */
+             continue;
+           /* We will take any letters or digits.  parse_number will
+              complain if past the radix, or if L or U are not final.  */
+           else if ((*p < '0' || *p > '9')
+                    && ((*p < 'a' || *p > 'z')
+                                 && (*p < 'A' || *p > 'Z')))
+             break;
+         }
+       toktype = parse_number (tokstart, p - tokstart, got_dot|got_e, &yylval);
+        if (toktype == ERROR)
+         {
+           char *err_copy = (char *) alloca (p - tokstart + 1);
+
+           memcpy (err_copy, tokstart, p - tokstart);
+           err_copy[p - tokstart] = 0;
+           error ("Invalid number \"%s\".", err_copy);
+         }
+       lexptr = p;
+       return toktype;
+      }
+
+    case '+':
+    case '-':
+    case '*':
+    case '/':
+    case '%':
+    case '|':
+    case '&':
+    case '^':
+    case '~':
+    case '!':
+    case '<':
+    case '>':
+    case '[':
+    case ']':
+    case '?':
+    case ':':
+    case '=':
+    case '{':
+    case '}':
+    symbol:
+      lexptr++;
+      return c;
+
+    case '"':
+
+      /* Build the gdb internal form of the input string in tempbuf,
+        translating any standard C escape forms seen.  Note that the
+        buffer is null byte terminated *only* for the convenience of
+        debugging gdb itself and printing the buffer contents when
+        the buffer contains no embedded nulls.  Gdb does not depend
+        upon the buffer being null byte terminated, it uses the length
+        string instead.  This allows gdb to handle C strings (as well
+        as strings in other languages) with embedded null bytes */
+
+      tokptr = ++tokstart;
+      tempbufindex = 0;
+
+      do {
+       /* Grow the static temp buffer if necessary, including allocating
+          the first one on demand. */
+       if (tempbufindex + 1 >= tempbufsize)
+         {
+           tempbuf = (char *) realloc (tempbuf, tempbufsize += 64);
+         }
+       switch (*tokptr)
+         {
+         case '\0':
+         case '"':
+           /* Do nothing, loop will terminate. */
+           break;
+         case '\\':
+           tokptr++;
+           c = parse_escape (&tokptr);
+           if (c == -1)
+             {
+               continue;
+             }
+           tempbuf[tempbufindex++] = c;
+           break;
+         default:
+           tempbuf[tempbufindex++] = *tokptr++;
+           break;
+         }
+      } while ((*tokptr != '"') && (*tokptr != '\0'));
+      if (*tokptr++ != '"')
+       {
+         error ("Unterminated string in expression.");
+       }
+      tempbuf[tempbufindex] = '\0';    /* See note above */
+      yylval.sval.ptr = tempbuf;
+      yylval.sval.length = tempbufindex;
+      lexptr = tokptr;
+      return (STRING_LITERAL);
+    }
+
+  if (!(c == '_' || c == '$'
+       || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')))
+    /* We must have come across a bad character (e.g. ';').  */
+    error ("Invalid character '%c' in expression.", c);
+
+  /* It's a name.  See how long it is.  */
+  namelen = 0;
+  for (c = tokstart[namelen];
+       (c == '_' || c == '$' || (c >= '0' && c <= '9')
+       || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '<');)
+    {
+       if (c == '<')
+        {
+          int i = namelen;
+          while (tokstart[++i] && tokstart[i] != '>');
+          if (tokstart[i] == '>')
+            namelen = i;
+         }
+       c = tokstart[++namelen];
+     }
+
+  /* The token "if" terminates the expression and is NOT 
+     removed from the input stream.  */
+  if (namelen == 2 && tokstart[0] == 'i' && tokstart[1] == 'f')
+    {
+      return 0;
+    }
+
+  lexptr += namelen;
+
+  tryname:
+
+  /* Catch specific keywords.  Should be done with a data structure.  */
+  switch (namelen)
+    {
+    case 7:
+      if (STREQN (tokstart, "boolean", 7))
+       return BOOLEAN;
+      break;
+    case 6:
+      if (STREQN (tokstart, "double", 6))      
+       return DOUBLE;
+      break;
+    case 5:
+      if (STREQN (tokstart, "short", 5))
+       return SHORT;
+      if (STREQN (tokstart, "false", 5))
+       return FALSE;
+      if (STREQN (tokstart, "super", 5))
+       return SUPER;
+      if (STREQN (tokstart, "float", 5))
+       return FLOAT;
+      break;
+    case 4:
+      if (STREQN (tokstart, "long", 4))
+       return LONG;
+      if (STREQN (tokstart, "byte", 4))
+       return BYTE;
+      if (STREQN (tokstart, "char", 4))
+       return CHAR;
+      if (STREQN (tokstart, "true", 4))
+       return TRUE;
+      if (current_language->la_language == language_cplus
+         && STREQN (tokstart, "this", 4))
+       {
+         static const char this_name[] =
+                                { CPLUS_MARKER, 't', 'h', 'i', 's', '\0' };
+
+         if (lookup_symbol (this_name, expression_context_block,
+                            VAR_NAMESPACE, (int *) NULL,
+                            (struct symtab **) NULL))
+           return THIS;
+       }
+      break;
+    case 3:
+      if (STREQN (tokstart, "int", 3))
+       return INT;
+      if (STREQN (tokstart, "new", 3))
+       return NEW;
+      break;
+    default:
+      break;
+    }
+
+  yylval.sval.ptr = tokstart;
+  yylval.sval.length = namelen;
+
+  if (*tokstart == '$')
+    {
+      write_dollar_variable (yylval.sval);
+      return VARIABLE;
+    }
+
+  /* Input names that aren't symbols but ARE valid hex numbers,
+     when the input radix permits them, can be names or numbers
+     depending on the parse.  Note we support radixes > 16 here.  */
+  if (((tokstart[0] >= 'a' && tokstart[0] < 'a' + input_radix - 10) ||
+       (tokstart[0] >= 'A' && tokstart[0] < 'A' + input_radix - 10)))
+    {
+      YYSTYPE newlval; /* Its value is ignored.  */
+      int hextype = parse_number (tokstart, namelen, 0, &newlval);
+      if (hextype == INTEGER_LITERAL)
+       return NAME_OR_INT;
+    }
+  return IDENTIFIER;
+}
+
+void
+yyerror (msg)
+     char *msg;
+{
+  error ("A %s in expression, near `%s'.", (msg ? msg : "error"), lexptr);
+}
+
+static struct type *
+java_type_from_name (name)
+     struct stoken name;
+{
+  char *tmp = copy_name (name);
+  struct type *typ = java_lookup_class (tmp);
+  if (typ == NULL || TYPE_CODE (typ) != TYPE_CODE_STRUCT)
+    error ("No class named %s.", tmp);
+  return typ;
+}
+
+static void
+push_variable (name)
+     struct stoken name;
+{
+  char *tmp = copy_name (name);
+  int is_a_field_of_this = 0;
+  struct symbol *sym;
+  struct type *typ;
+  sym = lookup_symbol (tmp, expression_context_block, VAR_NAMESPACE,
+                      &is_a_field_of_this, (struct symtab **) NULL);
+  if (sym)
+    {
+      if (symbol_read_needs_frame (sym))
+       {
+         if (innermost_block == 0 ||
+             contained_in (block_found, innermost_block))
+           innermost_block = block_found;
+       }
+
+      write_exp_elt_opcode (OP_VAR_VALUE);
+      /* We want to use the selected frame, not another more inner frame
+        which happens to be in the same block.  */
+      write_exp_elt_block (NULL);
+      write_exp_elt_sym (sym);
+      write_exp_elt_opcode (OP_VAR_VALUE);
+      return;
+    }
+  if (is_a_field_of_this)
+    {
+      /* it hangs off of `this'.  Must not inadvertently convert from a
+        method call to data ref.  */
+      if (innermost_block == 0 || 
+         contained_in (block_found, innermost_block))
+       innermost_block = block_found;
+      write_exp_elt_opcode (OP_THIS);
+      write_exp_elt_opcode (OP_THIS);
+      write_exp_elt_opcode (STRUCTOP_PTR);
+      write_exp_string (name);
+      write_exp_elt_opcode (STRUCTOP_PTR);
+      return;
+    }
+
+  typ = java_lookup_class (tmp);
+  if (typ != NULL)
+    {
+      write_exp_elt_opcode(OP_TYPE);
+      write_exp_elt_type(typ);
+      write_exp_elt_opcode(OP_TYPE);
+    }
+  else
+    {
+      struct minimal_symbol *msymbol;
+
+      msymbol = lookup_minimal_symbol (tmp, NULL, NULL);
+      if (msymbol != NULL)
+       {
+         write_exp_msymbol (msymbol,
+                            lookup_function_type (builtin_type_int),
+                            builtin_type_int);
+       }
+      else if (!have_full_symbols () && !have_partial_symbols ())
+       error ("No symbol table is loaded.  Use the \"file\" command.");
+      else
+       error ("No symbol \"%s\" in current context.", tmp);
+    }
+
+}
diff --git a/gdb/java-lang.c b/gdb/java-lang.c
new file mode 100644 (file)
index 0000000..a3bee65
--- /dev/null
@@ -0,0 +1,727 @@
+/* Java language support routines for GDB, the GNU debugger.
+   Copyright 1997 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program 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 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "parser-defs.h"
+#include "language.h"
+#include "gdbtypes.h"
+#include "symtab.h"
+#include "symfile.h"
+#include "objfiles.h"
+#include "gdb_string.h"
+#include "value.h"
+#include "c-lang.h"
+#include "java-lang.h"
+
+struct type *java_int_type;
+struct type *java_byte_type;
+struct type *java_short_type;
+struct type *java_long_type;
+struct type *java_boolean_type;
+struct type *java_char_type;
+struct type *java_float_type;
+struct type *java_double_type;
+struct type *java_void_type;
+
+struct type *java_object_type;
+
+/* This objfile contains symtabs that have been dynamically created
+   to record dynamically loaded Java classes and dynamically
+   compiled java methods. */
+struct objfile *dynamics_objfile = NULL;
+
+struct objfile *
+get_dynamics_objfile ()
+{
+  if (dynamics_objfile == NULL)
+    {
+      dynamics_objfile = allocate_objfile (NULL, 0);
+    }
+  return dynamics_objfile;
+}
+
+#if 1
+/* symtab contains classes read from the inferior. */
+
+static struct symtab *class_symtab = NULL;
+
+/* Maximum number of class in class_symtab before relocation is needed. */
+
+static int class_symtab_space;
+
+struct symtab *
+get_java_class_symtab ()
+{
+  if (class_symtab == NULL)
+    {
+      struct objfile *objfile = get_dynamics_objfile();
+      struct blockvector *bv;
+      struct block *bl;
+      class_symtab = allocate_symtab ("<java-classes>", objfile);
+      class_symtab->language = language_java;
+      bv = (struct blockvector *)
+       obstack_alloc (&objfile->symbol_obstack, sizeof (struct blockvector));
+      BLOCKVECTOR_NBLOCKS (bv) = 1;
+      BLOCKVECTOR (class_symtab) = bv;
+
+      /* Allocate dummy STATIC_BLOCK. */
+      bl = (struct block *)
+       obstack_alloc (&objfile->symbol_obstack, sizeof (struct block));
+      BLOCK_NSYMS (bl) = 0;
+      BLOCK_START (bl) = 0;
+      BLOCK_END (bl) = 0;
+      BLOCK_FUNCTION (bl) = NULL;
+      BLOCK_SUPERBLOCK (bl) = NULL;
+      BLOCK_GCC_COMPILED (bl) = 0;
+      BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK) = bl;
+
+      /* Allocate GLOBAL_BLOCK.  This has to be relocatable. */
+      class_symtab_space = 128;
+      bl = (struct block *)
+       mmalloc (objfile->md,
+                sizeof (struct block)
+                + ((class_symtab_space - 1) * sizeof (struct symbol *)));
+      *bl = *BLOCKVECTOR_BLOCK (bv, STATIC_BLOCK);
+      BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
+      class_symtab->free_ptr = (char *) bl;
+    }
+  return class_symtab;
+}
+
+static void
+add_class_symtab_symbol (sym)
+     struct symbol *sym;
+{
+  struct symtab *symtab = get_java_class_symtab ();
+  struct blockvector *bv = BLOCKVECTOR (symtab);
+  struct block *bl = BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK);
+  if (BLOCK_NSYMS (bl) >= class_symtab_space)
+    {
+      /* Need to re-allocate. */
+      class_symtab_space *= 2;
+      bl = (struct block *)
+       mrealloc (symtab->objfile->md, bl,
+                 sizeof (struct block)
+                 + ((class_symtab_space - 1) * sizeof (struct symbol *)));
+      class_symtab->free_ptr = (char *) bl;
+      BLOCKVECTOR_BLOCK (bv, GLOBAL_BLOCK) = bl;
+    }
+  
+  BLOCK_SYM (bl, BLOCK_NSYMS (bl)) = sym;
+  BLOCK_NSYMS (bl) = BLOCK_NSYMS (bl) + 1;
+}
+
+struct symbol *
+add_class_symbol (type, addr)
+     struct type *type;
+     CORE_ADDR addr;
+{
+  struct symbol *sym;
+  sym = (struct symbol *)
+    obstack_alloc (&dynamics_objfile->symbol_obstack, sizeof (struct symbol));
+  memset (sym, 0, sizeof (struct symbol));
+  SYMBOL_LANGUAGE (sym) = language_java;
+  SYMBOL_NAME (sym) = TYPE_NAME (type);
+  SYMBOL_CLASS (sym) = LOC_TYPEDEF;
+  /*  SYMBOL_VALUE (sym) = valu;*/
+  SYMBOL_TYPE (sym) = type;
+  SYMBOL_NAMESPACE (sym) = STRUCT_NAMESPACE;
+  SYMBOL_VALUE_ADDRESS (sym) = addr;
+  return sym;
+}
+#endif
+
+struct type *
+java_lookup_class (name)
+     char *name;
+{
+  struct symbol *sym;
+  sym = lookup_symbol (name, expression_context_block, STRUCT_NAMESPACE,
+                      (int *) 0, (struct symtab **) NULL);
+  if (sym == NULL)
+    {
+      /* FIXME - should search inferior's symbol table. */
+      return NULL;
+    }
+  return SYMBOL_TYPE (sym);
+}
+
+/* Return a nul-terminated string (allocated on OBSTACK) for
+   a name given by NAME (which has type Utf8Const*). */
+
+char *
+get_java_utf8_name (obstack, name)
+     struct obstack *obstack;
+     value_ptr name;
+{
+  char *chrs;
+  value_ptr temp = name;
+  int name_length = (int) value_as_long
+    (value_struct_elt (&temp, NULL, "length", NULL, "structure"));
+  temp = name;
+  temp = value_struct_elt (&temp, NULL, "data", NULL, "structure");
+  chrs = obstack_alloc (obstack, name_length+1);
+  chrs [name_length] = '\0';
+  read_memory_section (VALUE_ADDRESS (temp) + VALUE_OFFSET (temp),
+                      chrs, name_length, NULL);
+  return chrs;
+}
+
+value_ptr
+java_class_from_object (obj_val)
+     value_ptr obj_val;
+{
+  value_ptr dtable_val = value_struct_elt (&obj_val, NULL, "dtable", NULL, "structure");
+  return value_struct_elt (&dtable_val, NULL, "class", NULL, "structure");
+}
+
+/* Check if CLASS_IS_PRIMITIVE(value of clas): */
+int
+java_class_is_primitive (clas)
+     value_ptr clas;
+{
+  value_ptr dtable = value_struct_elt (&clas, NULL, "dtable", NULL, "struct");
+  CORE_ADDR i = value_as_pointer (dtable);
+  return (int) (i & 0x7fffffff) == (int) 0x7fffffff;
+}
+
+/* Read a Kaffe Class object, and generated a gdb (TYPE_CODE_STRUCT) type. */
+
+struct type *
+type_from_class (clas)
+     value_ptr clas;
+{
+  struct type *type;
+  struct type *tsuper;
+  int ninterfaces, nfields;
+  char *name;
+  value_ptr temp;
+  struct objfile *objfile = get_dynamics_objfile();
+  value_ptr utf8_name, fields, field, method, methods;
+  int name_length;
+  char *nptr;
+  CORE_ADDR addr;
+  struct block *bl;
+  int i, j;
+  int type_is_object = 0;
+  int is_array = 0;
+  int nmethods;
+  struct fn_field *fn_fields;
+  struct fn_fieldlist *fn_fieldlists;
+  char *unqualified_name;
+
+  type = check_typedef (VALUE_TYPE (clas));
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    {
+      if (value_logical_not (clas))
+       return NULL;
+      clas = value_ind (clas);
+    }
+  addr = VALUE_ADDRESS (clas) + VALUE_OFFSET (clas);
+
+  get_java_class_symtab ();
+  bl = BLOCKVECTOR_BLOCK (BLOCKVECTOR (class_symtab), GLOBAL_BLOCK);
+  for (i = BLOCK_NSYMS (bl);  --i >= 0; )
+    {
+      struct symbol *sym = BLOCK_SYM (bl, i);
+      if (SYMBOL_VALUE_ADDRESS (sym) == addr)
+       return SYMBOL_TYPE (sym);
+    }
+
+  if (java_class_is_primitive (clas))
+    {
+      value_ptr sig;
+      temp = clas;
+      sig = value_struct_elt (&temp, NULL, "msize", NULL, "structure");
+      return java_primitive_type (value_as_long (sig));
+    }
+
+  /* Get Class name. */
+  /* if clasloader non-null, prepend loader address. FIXME */
+  temp = clas;
+  utf8_name = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+  name = get_java_utf8_name (&objfile->type_obstack, utf8_name);
+
+  type = alloc_type (objfile);
+  TYPE_CODE (type) = TYPE_CODE_STRUCT;
+  INIT_CPLUS_SPECIFIC (type);
+
+  if (name[0] == '[')
+    {
+      is_array = 1;
+      temp = clas;
+      /* Set array element type. */
+      temp = value_struct_elt (&temp, NULL, "methods", NULL, "structure");
+      VALUE_TYPE (temp) = lookup_pointer_type (VALUE_TYPE (clas));
+      TYPE_TARGET_TYPE (type) = type_from_class (temp);
+    }
+  unqualified_name = name;
+  for (nptr = name;  *nptr != 0;  nptr++)
+    {
+      if (*nptr == '/')
+       {
+         *nptr = '.';
+         unqualified_name = nptr+1;
+       }
+    }
+
+  ALLOCATE_CPLUS_STRUCT_TYPE (type);
+  TYPE_NAME (type) = name;
+
+  add_class_symtab_symbol (add_class_symbol (type, addr));
+
+  temp = clas;
+  temp = value_struct_elt (&temp, NULL, "superclass", NULL, "structure");
+  if (name != NULL && strcmp (name, "java.lang.Object") == 0)
+    {
+      tsuper = get_java_object_type ();
+      if (tsuper && TYPE_CODE (tsuper) == TYPE_CODE_PTR)
+       tsuper = TYPE_TARGET_TYPE (tsuper);
+      type_is_object = 1;
+    }
+  else
+    tsuper = type_from_class (temp);
+
+#if 1
+  ninterfaces = 0;
+#else
+  temp = clas;
+  ninterfaces = value_as_long (value_struct_elt (&temp, NULL, "interface_len", NULL, "structure"));
+#endif
+  TYPE_N_BASECLASSES (type) = (tsuper == NULL ? 0 : 1) + ninterfaces;
+  temp = clas;
+  nfields = value_as_long (value_struct_elt (&temp, NULL, "nfields", NULL, "structure"));
+  nfields += TYPE_N_BASECLASSES (type);
+  TYPE_NFIELDS (type) = nfields;
+  TYPE_FIELDS (type) = (struct field *)
+    TYPE_ALLOC (type, sizeof (struct field) * nfields);
+
+  memset (TYPE_FIELDS (type), 0, sizeof (struct field) * nfields);
+
+  TYPE_FIELD_PRIVATE_BITS (type) =
+    (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_PRIVATE_BITS (type), nfields);
+
+  TYPE_FIELD_PROTECTED_BITS (type) =
+    (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_PROTECTED_BITS (type), nfields);
+
+  TYPE_FIELD_IGNORE_BITS (type) =
+    (B_TYPE *) TYPE_ALLOC (type, B_BYTES (nfields));
+  B_CLRALL (TYPE_FIELD_IGNORE_BITS (type), nfields);
+
+  TYPE_FIELD_VIRTUAL_BITS (type) = (B_TYPE *)
+    TYPE_ALLOC (type, B_BYTES (TYPE_N_BASECLASSES (type)));
+  B_CLRALL (TYPE_FIELD_VIRTUAL_BITS (type), TYPE_N_BASECLASSES (type));
+
+  if (tsuper != NULL)
+    {
+      TYPE_BASECLASS (type, 0) = tsuper;
+      if (type_is_object)
+       SET_TYPE_FIELD_PRIVATE (type, 0);
+    }
+
+
+  temp = clas;
+  temp = value_struct_elt (&temp, NULL, "bfsize", NULL, "structure");
+  TYPE_LENGTH (type) = JAVA_OBJECT_SIZE + value_as_long (temp);
+
+  fields = NULL;
+  for (i = TYPE_N_BASECLASSES (type);  i < nfields;  i++)
+    {
+      int accflags;
+      int boffset;
+      struct type *ftype;
+      if (fields == NULL)
+       {
+         temp = clas;
+         fields = value_struct_elt (&temp, NULL, "fields", NULL, "structure");
+         field = value_ind (fields);
+       }
+      else
+       { /* Re-use field value for next field. */
+         VALUE_ADDRESS (field) += TYPE_LENGTH (VALUE_TYPE (field));
+         VALUE_LAZY (field) = 1;
+       }
+      temp = field;
+      temp = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+      TYPE_FIELD_NAME (type, i) =
+       get_java_utf8_name (&objfile->type_obstack, temp);
+      temp = field;
+      accflags = value_as_long (value_struct_elt (&temp, NULL, "accflags",
+                                                 NULL, "structure"));
+      boffset = value_as_long (value_struct_elt (&temp, NULL, "boffset",
+                                                 NULL, "structure"));
+      if (accflags & 0x0001) /* public access */
+       {
+         /* ??? */
+       }
+      if (accflags & 0x0002) /* private access */
+       {
+         SET_TYPE_FIELD_PRIVATE (type, i);
+       }
+      if (accflags & 0x0004) /* protected access */
+       {
+         SET_TYPE_FIELD_PROTECTED (type, i);
+       }
+      if (accflags & 0x0008)  /* ACC_STATIC */
+       {
+         TYPE_FIELD_BITPOS (type, i) = -1;
+         /* Hack for TYPE_FIELD_STATIC_PHYSNAME to prevent a crash. FIXME. */
+         type->fields[i].bitsize = (long) "???";
+       }
+      else
+       TYPE_FIELD_BITPOS (type, i) = 8 * (JAVA_OBJECT_SIZE + boffset);
+      if (accflags & 0x8000) /* FIELD_UNRESOLVED_FLAG */
+       {
+         TYPE_FIELD_TYPE (type, i) = get_java_object_type (); /* FIXME */
+       }
+      else
+       {
+         struct type *ftype;
+         temp = field;
+         temp = value_struct_elt (&temp, NULL, "type", NULL, "structure");
+         ftype = type_from_class (temp);
+         if (TYPE_CODE (ftype) == TYPE_CODE_STRUCT)
+           ftype = lookup_pointer_type (ftype);
+         TYPE_FIELD_TYPE (type, i) = ftype;
+       }
+    }
+
+  temp = clas;
+  nmethods = value_as_long (value_struct_elt (&temp, NULL, "nmethods",
+                                             NULL, "structure"));
+  TYPE_NFN_FIELDS_TOTAL (type) = nmethods;
+  j = nmethods * sizeof (struct fn_field);
+  fn_fields = (struct fn_field*)
+    obstack_alloc (&dynamics_objfile->symbol_obstack, j);
+  memset (fn_fields, 0, j);
+  fn_fieldlists = (struct fn_fieldlist*)
+    alloca (nmethods * sizeof (struct fn_fieldlist));
+
+  methods = NULL;
+  for (i = 0;  i < nmethods;  i++)
+    {
+      char *mname;
+      int k;
+      if (methods == NULL)
+       {
+         temp = clas;
+         methods = value_struct_elt (&temp, NULL, "methods", NULL, "structure");
+         method = value_ind (methods);
+       }
+      else
+       { /* Re-use method value for next method. */
+         VALUE_ADDRESS (method) += TYPE_LENGTH (VALUE_TYPE (method));
+         VALUE_LAZY (method) = 1;
+       }
+
+      /* Get method name. */
+      temp = method;
+      temp = value_struct_elt (&temp, NULL, "name", NULL, "structure");
+      mname = get_java_utf8_name (&objfile->type_obstack, temp);
+      if (strcmp (mname, "<init>") == 0)
+       mname = unqualified_name;
+
+      /* Check for an existing method with the same name.
+       * This makes building the fn_fieldslists an O(nmethods**2)
+       * operation.  That could be using hashing, but I doubt it
+       * is worth it.  Note that we do maintain the order of methods
+       * in the inferior's Method table (as long as that is grouped
+       * by method name), which I think is desirable.  --PB */
+      for (k = 0, j = TYPE_NFN_FIELDS (type);  ; )
+       {
+         if (--j < 0)
+           { /* No match - new method name. */
+             j = TYPE_NFN_FIELDS(type)++;
+             fn_fieldlists[j].name = mname;
+             fn_fieldlists[j].length = 1;
+             fn_fieldlists[j].fn_fields = &fn_fields[i];
+             k = i;
+             break;
+           }
+         if (strcmp (mname, fn_fieldlists[j].name) == 0)
+           { /* Found an existing method with the same name. */
+             int l;
+             if (mname != unqualified_name)
+               obstack_free (&objfile->type_obstack, mname);
+             mname = fn_fieldlists[j].name;
+             fn_fieldlists[j].length++;
+             k = i - k;  /* Index of new slot. */
+             /* Shift intervening fn_fields (between k and i) down. */
+             for (l = i;  l > k;  l--) fn_fields[l] = fn_fields[l-1];
+             for (l = TYPE_NFN_FIELDS (type);  --l > j; )
+               fn_fieldlists[l].fn_fields++;
+             break;
+           }
+         k += fn_fieldlists[j].length;
+       }
+      fn_fields[k].physname = "";
+      fn_fields[k].is_stub = 1;
+      fn_fields[k].type = make_function_type (java_void_type, NULL); /* FIXME*/
+      TYPE_CODE (fn_fields[k].type) = TYPE_CODE_METHOD;
+    }
+
+  j = TYPE_NFN_FIELDS(type) * sizeof (struct fn_fieldlist);
+  TYPE_FN_FIELDLISTS (type) = (struct fn_fieldlist*)
+    obstack_alloc (&dynamics_objfile->symbol_obstack, j);
+  memcpy (TYPE_FN_FIELDLISTS (type), fn_fieldlists, j);
+  return type;
+}
+
+struct type*
+get_java_object_type ()
+{
+  return java_object_type;
+}
+
+int
+is_object_type (type)
+     struct type *type;
+{
+  CHECK_TYPEDEF (type);
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    {
+      struct type *ttype = check_typedef (TYPE_TARGET_TYPE (type));
+      char *name;
+      if (TYPE_CODE (ttype) != TYPE_CODE_STRUCT)
+       return 0;
+      while (TYPE_N_BASECLASSES (ttype) > 0)
+       ttype = TYPE_BASECLASS (ttype, 0);
+      name = TYPE_NAME (ttype);
+      if (name != NULL && strcmp (name, "java.lang.Object") == 0)
+       return 1;
+      name = TYPE_NFIELDS (ttype) > 0 ? TYPE_FIELD_NAME (ttype, 0) : (char*)0;
+      if (name != NULL && strcmp (name, "dtable") == 0)
+       {
+         if (java_object_type == NULL)
+           java_object_type = type;
+         return 1;
+       }
+    }
+  return 0;
+}
+
+struct type*
+java_primitive_type (signature)
+     int signature;
+{
+  switch (signature)
+    {
+    case 'B':  return java_byte_type;
+    case 'S':  return java_short_type;
+    case 'I':  return java_int_type;
+    case 'J':  return java_long_type;
+    case 'Z':  return java_boolean_type;
+    case 'C':  return java_char_type;
+    case 'F':  return java_float_type;
+    case 'D':  return java_double_type;
+    case 'V':  return java_void_type;
+    }
+  error ("unknown signature '%c' for primitive type", (char) signature);
+}
+
+/* Return the type of TYPE followed by DIMS pairs of [ ].
+   If DIMS == 0, TYPE is returned. */
+
+struct type *
+java_array_type (type, dims)
+     struct type *type;
+     int dims;
+{
+  if (dims == 0)
+    return type;
+  error ("array types not implemented");
+}
+
+/* Create a Java string in the inferior from a (Utf8) literal. */
+
+value_ptr
+java_value_string (ptr, len)
+     char *ptr;
+     int len;
+{
+  error ("not implemented - java_value_string"); /* FIXME */
+}
+
+static value_ptr
+evaluate_subexp_java (expect_type, exp, pos, noside)
+     struct type *expect_type;
+     register struct expression *exp;
+     register int *pos;
+     enum noside noside;
+{
+  int pc = *pos;
+  int i;
+  enum exp_opcode op = exp->elts[*pos].opcode;
+  value_ptr arg1;
+  switch (op)
+    {
+    case UNOP_IND:
+      if (noside == EVAL_SKIP)
+       goto standard;
+      (*pos)++;
+      arg1 = evaluate_subexp_standard (expect_type, exp, pos, EVAL_NORMAL);
+      if (is_object_type (VALUE_TYPE (arg1)))
+       {
+         struct type *type = type_from_class (java_class_from_object (arg1));
+         arg1 = value_cast (lookup_pointer_type (type), arg1);
+       }
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      return value_ind (arg1);
+    case OP_STRING:
+      (*pos)++;
+      i = longest_to_int (exp->elts[pc + 1].longconst);
+      (*pos) += 3 + BYTES_TO_EXP_ELEM (i + 1);
+      if (noside == EVAL_SKIP)
+       goto nosideret;
+      return java_value_string (&exp->elts[pc + 2].string, i);
+    }
+standard:
+  return evaluate_subexp_standard (expect_type, exp, pos, noside);
+ nosideret:
+  return value_from_longest (builtin_type_long, (LONGEST) 1);
+}
+
+static struct type *
+java_create_fundamental_type (objfile, typeid)
+     struct objfile *objfile;
+     int typeid;
+{
+  switch (typeid)
+    {
+    case FT_VOID:           return java_void_type;
+    case FT_BOOLEAN:        return java_boolean_type;
+    case FT_CHAR:           return java_char_type;
+    case FT_FLOAT:          return java_float_type;
+    case FT_DBL_PREC_FLOAT: return java_double_type;
+    case FT_BYTE: case FT_SIGNED_CHAR:       return java_byte_type;
+    case FT_SHORT: case FT_SIGNED_SHORT:     return java_short_type;
+    case FT_INTEGER: case FT_SIGNED_INTEGER: return java_int_type;
+    case FT_LONG: case FT_SIGNED_LONG:       return java_long_type;
+    }
+  return c_create_fundamental_type (objfile, typeid);
+}
+
+/* Table mapping opcodes into strings for printing operators
+   and precedences of the operators.  */
+
+const struct op_print java_op_print_tab[] =
+  {
+    {",",  BINOP_COMMA, PREC_COMMA, 0},
+    {"=",  BINOP_ASSIGN, PREC_ASSIGN, 1},
+    {"||", BINOP_LOGICAL_OR, PREC_LOGICAL_OR, 0},
+    {"&&", BINOP_LOGICAL_AND, PREC_LOGICAL_AND, 0},
+    {"|",  BINOP_BITWISE_IOR, PREC_BITWISE_IOR, 0},
+    {"^",  BINOP_BITWISE_XOR, PREC_BITWISE_XOR, 0},
+    {"&",  BINOP_BITWISE_AND, PREC_BITWISE_AND, 0},
+    {"==", BINOP_EQUAL, PREC_EQUAL, 0},
+    {"!=", BINOP_NOTEQUAL, PREC_EQUAL, 0},
+    {"<=", BINOP_LEQ, PREC_ORDER, 0},
+    {">=", BINOP_GEQ, PREC_ORDER, 0},
+    {">",  BINOP_GTR, PREC_ORDER, 0},
+    {"<",  BINOP_LESS, PREC_ORDER, 0},
+    {">>", BINOP_RSH, PREC_SHIFT, 0},
+    {"<<", BINOP_LSH, PREC_SHIFT, 0},
+#if 0
+    {">>>", BINOP_???, PREC_SHIFT, 0},
+#endif
+    {"+",  BINOP_ADD, PREC_ADD, 0},
+    {"-",  BINOP_SUB, PREC_ADD, 0},
+    {"*",  BINOP_MUL, PREC_MUL, 0},
+    {"/",  BINOP_DIV, PREC_MUL, 0},
+    {"%",  BINOP_REM, PREC_MUL, 0},
+    {"-",  UNOP_NEG, PREC_PREFIX, 0},
+    {"!",  UNOP_LOGICAL_NOT, PREC_PREFIX, 0},
+    {"~",  UNOP_COMPLEMENT, PREC_PREFIX, 0},
+    {"*",  UNOP_IND, PREC_PREFIX, 0},
+#if 0
+    {"instanceof", ???, ???, 0},
+#endif
+    {"++", UNOP_PREINCREMENT, PREC_PREFIX, 0},
+    {"--", UNOP_PREDECREMENT, PREC_PREFIX, 0},
+    {NULL, 0, 0, 0}
+};
+
+const struct language_defn java_language_defn = {
+  "java",                              /* Language name */
+  language_java,
+  c_builtin_types,
+  range_check_off,
+  type_check_off,
+  java_parse,
+  java_error,
+  evaluate_subexp_java,
+  c_printchar,                 /* Print a character constant */
+  c_printstr,                  /* Function to print string constant */
+  java_create_fundamental_type,        /* Create fundamental type in this language */
+  c_print_type,                        /* Print a type using appropriate syntax */
+  java_val_print,              /* Print a value using appropriate syntax */
+  java_value_print,            /* Print a top-level value */
+  {"",      "",    "",   ""},  /* Binary format info */
+  {"0%lo",   "0",   "o",  ""}, /* Octal format info */
+  {"%ld",    "",    "d",  ""}, /* Decimal format info */
+  {"0x%lx",  "0x",  "x",  ""}, /* Hex format info */
+  java_op_print_tab,           /* expression operators for printing */
+  1,                           /* c-style arrays */
+  0,                           /* String lower bound */
+  &builtin_type_char,          /* Type of string elements */ 
+  LANG_MAGIC
+};
+
+void
+_initialize_jave_language ()
+{
+
+  java_int_type    = init_type (TYPE_CODE_INT,  4, 0, "int", NULL);
+  java_short_type  = init_type (TYPE_CODE_INT,  2, 0, "short", NULL);
+  java_long_type   = init_type (TYPE_CODE_INT,  8, 0, "long", NULL);
+  java_byte_type   = init_type (TYPE_CODE_INT,  1, 0, "byte", NULL);
+  java_boolean_type= init_type (TYPE_CODE_BOOL, 1, 0, "boolean", NULL);
+  java_char_type   = init_type (TYPE_CODE_CHAR, 2, 0, "char", NULL);
+  java_float_type  = init_type (TYPE_CODE_FLT,  4, 0, "float", NULL);
+  java_double_type = init_type (TYPE_CODE_FLT,  8, 0, "double", NULL);
+  java_void_type   = init_type (TYPE_CODE_VOID, 1, 0, "void", NULL);
+
+  add_language (&java_language_defn);
+}
+
+/* Cleanup code that should be urn on every "run".
+   We need some hook to have this actually be called ... FIXME */
+
+void java_rerun_cleanup ()
+{
+  if (class_symtab != NULL)
+    {
+      free_symtab (class_symtab); /* ??? */
+      class_symtab = NULL;
+    }
+  if (dynamics_objfile != NULL)
+    {
+      free_objfile (dynamics_objfile);
+      dynamics_objfile = NULL;
+    }
+
+  java_object_type = NULL;
+}
diff --git a/gdb/java-lang.h b/gdb/java-lang.h
new file mode 100644 (file)
index 0000000..20f8b40
--- /dev/null
@@ -0,0 +1,63 @@
+/* Java language support definitions for GDB, the GNU debugger.
+   Copyright 1997 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program 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 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+extern int
+java_parse PARAMS ((void));    /* Defined in java-exp.y */
+
+extern void
+java_error PARAMS ((char *));  /* Defined in java-exp.y */
+
+#define JAVA_OBJECT_SIZE (6 * 4)  /* sizeof (struct Object) FIXME ! */
+
+extern struct type *java_int_type;
+extern struct type *java_byte_type;
+extern struct type *java_short_type;
+extern struct type *java_long_type;
+extern struct type *java_boolean_type;
+extern struct type *java_char_type;
+extern struct type *java_float_type;
+extern struct type *java_double_type;
+extern struct type *java_void_type;
+
+/* This objfile contains symtabs that have been dynamically created
+   to record dynamically loaded Java classes and dynamically
+   compiled java methods. */
+extern struct objfile *dynamics_objfile;
+
+extern int
+java_val_print PARAMS ((struct type *, char *, CORE_ADDR, GDB_FILE *, int, int,
+                       int, enum val_prettyprint));
+
+extern int
+java_value_print PARAMS ((struct value *, GDB_FILE *, int,
+                         enum val_prettyprint));
+
+extern value_ptr java_class_from_object PARAMS ((value_ptr));
+
+extern struct type *type_from_class PARAMS ((struct value*));
+
+extern struct type *java_primitive_type PARAMS ((int));
+
+extern struct type *java_array_type PARAMS ((struct type*, int));
+
+extern struct type *get_java_object_type ();
+
+extern struct type * java_lookup_class PARAMS((char *));
+
+extern int is_object_type PARAMS ((struct type*));
diff --git a/gdb/java-valprint.c b/gdb/java-valprint.c
new file mode 100644 (file)
index 0000000..bc9f0ae
--- /dev/null
@@ -0,0 +1,74 @@
+/* Support for printing Java values for GDB, the GNU debugger.
+   Copyright 1997 Free Software Foundation, Inc.
+
+This file is part of GDB.
+
+This program 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 of the License, or
+(at your option) any later version.
+
+This program 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 this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+
+#include "defs.h"
+#include "symtab.h"
+#include "gdbtypes.h"
+#include "expression.h"
+#include "value.h"
+#include "demangle.h"
+#include "valprint.h"
+#include "language.h"
+#include "java-lang.h"
+
+int
+java_value_print (val, stream, format, pretty)
+     value_ptr val;
+     GDB_FILE *stream;
+     int format;
+     enum val_prettyprint pretty;
+{
+  struct type *type = VALUE_TYPE (val);
+  if (TYPE_CODE (type) == TYPE_CODE_PTR)
+    {
+      fprintf_filtered (stream, "(");
+      type_print (TYPE_TARGET_TYPE (type), "", stream, -1);
+      fprintf_filtered (stream, ") ");
+    }
+  return (val_print (VALUE_TYPE (val), VALUE_CONTENTS (val),
+                    VALUE_ADDRESS (val) + VALUE_OFFSET (val),
+                    stream, format, 1, 0, pretty));
+}
+
+int
+java_val_print (type, valaddr, address, stream, format, deref_ref, recurse,
+            pretty)
+     struct type *type;
+     char *valaddr;
+     CORE_ADDR address;
+     GDB_FILE *stream;
+     int format;
+     int deref_ref;
+     int recurse;
+     enum val_prettyprint pretty;
+{
+  if (is_object_type (type))
+    {
+      CORE_ADDR obj_addr = unpack_pointer (type, valaddr);
+      if (obj_addr != 0)
+       {
+         value_ptr obj_val
+           = value_at (TYPE_TARGET_TYPE (type), obj_addr, NULL);
+         type = type_from_class (java_class_from_object (obj_val));
+         type = lookup_pointer_type (type);
+       }
+    }
+  return c_val_print (type, valaddr, address, stream, format,
+                     deref_ref, recurse, pretty);
+}
index 65732936ec6f78081381d900089f582c5435ae1c..2a05eac98eb325f47c9abd2596ed651e94a41d47 100644 (file)
@@ -130,6 +130,7 @@ allocate_objfile (abfd, mapped)
   mapped |= mapped_symbol_files;
 
 #if !defined(NO_MMALLOC) && defined(HAVE_MMAP)
+  if (abfd != NULL)
   {
 
     /* If we can support mapped symbol files, try to open/reopen the
@@ -254,15 +255,18 @@ allocate_objfile (abfd, mapped)
     {
       mfree (objfile -> md, objfile -> name);
     }
-  objfile -> name = mstrsave (objfile -> md, bfd_get_filename (abfd));
-  objfile -> mtime = bfd_get_mtime (abfd);
+  if (abfd != NULL)
+    {
+      objfile -> name = mstrsave (objfile -> md, bfd_get_filename (abfd));
+      objfile -> mtime = bfd_get_mtime (abfd);
 
-  /* Build section table.  */
+      /* Build section table.  */
 
-  if (build_objfile_section_table (objfile))
-    {
-      error ("Can't find the file sections in `%s': %s", 
-            objfile -> name, bfd_errmsg (bfd_get_error ()));
+      if (build_objfile_section_table (objfile))
+       {
+         error ("Can't find the file sections in `%s': %s", 
+                objfile -> name, bfd_errmsg (bfd_get_error ()));
+       }
     }
 
   /* Add this file onto the tail of the linked list of other such files. */