From e0af926810ce20585d03be041c7d5be4aded0d6f Mon Sep 17 00:00:00 2001 From: "(no author)" <(no author)@138bc75d-0d04-0410-961f-82ee72b054a4> Date: Sun, 6 Sep 1998 15:36:06 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create branch 'egcs'. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/egcs@22300 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/java/Make-lang.in | 209 + gcc/java/Makefile.in | 258 ++ gcc/java/buffer.c | 50 + gcc/java/buffer.h | 43 + gcc/java/class.c | 1601 +++++++ gcc/java/config-lang.in | 40 + gcc/java/constants.c | 453 ++ gcc/java/convert.h | 24 + gcc/java/decl.c | 1561 +++++++ gcc/java/except.c | 278 ++ gcc/java/expr.c | 2283 ++++++++++ gcc/java/gjavah.c | 959 +++++ gcc/java/java-except.h | 67 + gcc/java/java-opcodes.h | 5 + gcc/java/java-tree.def | 12 + gcc/java/java-tree.h | 720 ++++ gcc/java/javaop.def | 314 ++ gcc/java/javaop.h | 142 + gcc/java/jcf-dump.c | 1072 +++++ gcc/java/jcf-io.c | 574 +++ gcc/java/jcf-parse.c | 917 ++++ gcc/java/jcf-reader.c | 352 ++ gcc/java/jcf-write.c | 964 +++++ gcc/java/jcf.h | 260 ++ gcc/java/jv-scan.c | 235 + gcc/java/jvgenmain.c | 124 + gcc/java/jvspec.c | 357 ++ gcc/java/keyword.gperf | 80 + gcc/java/keyword.h | 165 + gcc/java/lang-options.h | 35 + gcc/java/lang-specs.h | 38 + gcc/java/lang.c | 406 ++ gcc/java/lex.c | 1355 ++++++ gcc/java/lex.h | 512 +++ gcc/java/mangle.c | 163 + gcc/java/parse-scan.y | 1162 +++++ gcc/java/parse.c | 10648 ++++++++++++++++++++++++++++++++++++++++++++++ gcc/java/parse.h | 599 +++ gcc/java/parse.y | 8035 ++++++++++++++++++++++++++++++++++ gcc/java/typeck.c | 785 ++++ gcc/java/verify.c | 1239 ++++++ gcc/java/zextract.c | 350 ++ gcc/java/zipfile.h | 58 + 43 files changed, 39504 insertions(+) create mode 100644 gcc/java/Make-lang.in create mode 100644 gcc/java/Makefile.in create mode 100644 gcc/java/buffer.c create mode 100644 gcc/java/buffer.h create mode 100644 gcc/java/class.c create mode 100644 gcc/java/config-lang.in create mode 100644 gcc/java/constants.c create mode 100644 gcc/java/convert.h create mode 100644 gcc/java/decl.c create mode 100644 gcc/java/except.c create mode 100644 gcc/java/expr.c create mode 100644 gcc/java/gjavah.c create mode 100644 gcc/java/java-except.h create mode 100644 gcc/java/java-opcodes.h create mode 100644 gcc/java/java-tree.def create mode 100644 gcc/java/java-tree.h create mode 100644 gcc/java/javaop.def create mode 100644 gcc/java/javaop.h create mode 100644 gcc/java/jcf-dump.c create mode 100644 gcc/java/jcf-io.c create mode 100644 gcc/java/jcf-parse.c create mode 100644 gcc/java/jcf-reader.c create mode 100644 gcc/java/jcf-write.c create mode 100644 gcc/java/jcf.h create mode 100644 gcc/java/jv-scan.c create mode 100644 gcc/java/jvgenmain.c create mode 100644 gcc/java/jvspec.c create mode 100644 gcc/java/keyword.gperf create mode 100644 gcc/java/keyword.h create mode 100644 gcc/java/lang-options.h create mode 100644 gcc/java/lang-specs.h create mode 100644 gcc/java/lang.c create mode 100644 gcc/java/lex.c create mode 100644 gcc/java/lex.h create mode 100644 gcc/java/mangle.c create mode 100644 gcc/java/parse-scan.y create mode 100644 gcc/java/parse.c create mode 100644 gcc/java/parse.h create mode 100644 gcc/java/parse.y create mode 100644 gcc/java/typeck.c create mode 100644 gcc/java/verify.c create mode 100644 gcc/java/zextract.c create mode 100644 gcc/java/zipfile.h diff --git a/gcc/java/Make-lang.in b/gcc/java/Make-lang.in new file mode 100644 index 00000000000..de1adf43869 --- /dev/null +++ b/gcc/java/Make-lang.in @@ -0,0 +1,209 @@ +# Top level makefile fragment for the GNU compiler for the Java(TM) +# language. +# Copyright (C) 1996, 1998 Free Software Foundation, Inc. + +#This file is part of GNU CC. + +#GNU CC 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, +#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 +#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 provides the language dependent support in the main Makefile. +# Each language makefile fragment must provide the following targets: +# +# foo.all.build, foo.all.cross, foo.start.encap, foo.rest.encap, +# foo.info, foo.dvi, +# foo.install-normal, foo.install-common, foo.install-info, foo.install-man, +# foo.uninstall, foo.distdir, +# foo.mostlyclean, foo.clean, foo.distclean, foo.extraclean, +# foo.maintainer-clean, foo.stage1, foo.stage2, foo.stage3, foo.stage4 +# +# where `foo' is the name of the language. +# +# It should also provide rules for: +# +# - making any compiler driver (eg: g++) +# - the compiler proper (eg: jc1) +# - define the names for selecting the language in LANGUAGES. + +# Extra flags to pass to recursive makes. +JAVA_FLAGS_TO_PASS = \ + "JAVA_FOR_BUILD=$(JAVA_FOR_BUILD)" \ + "JAVAFLAGS=$(JAVAFLAGS)" \ + "JAVA_FOR_TARGET=$(JAVA_FOR_TARGET)" + +# Actual names to use when installing a native compiler. +JAVA_INSTALL_NAME = `t='$(program_transform_name)'; echo gcj | sed $$t` + +# Actual names to use when installing a cross-compiler. +JAVA_CROSS_NAME = `t='$(program_transform_cross_name)'; echo gcj | sed $$t` + + +# Define the names for selecting java in LANGUAGES. +java: jc1$(exeext) $(GCJ)$(exeext) jvgenmain$(exeext) gcjh$(exeext) + +# Define the name of target independant tools to be installed in $(bindir) +# Names are subject to changes +JAVA_TARGET_INDEPENDENT_BIN_TOOLS = gcjh jv-scan jcf-dump + +# Tell GNU make to ignore these if they exist. +.PHONY: java + +GCJ = gcj + +# Remember to keep this list in sync with JAVA_OBJS in Makefile.in!!! +# +JAVA_SRCS = $(srcdir)/java/parse.y $(srcdir)/java/class.c \ + $(srcdir)/java/decl.c $(srcdir)/java/expr.c $(srcdir)/java/constants.c \ + $(srcdir)/java/lang.c $(srcdir)/java/typeck.c $(srcdir)/java/except.c \ + $(srcdir)/java/verify.c $(srcdir)/java/zextract.c $(srcdir)/java/jcf-io.c \ + $(srcdir)/java/jcf-parse.c $(srcdir)/java/mangle.c \ + $(srcdir)/java/jcf-write.c $(srcdir)/java/buffer.c + +jc1$(exeext): $(P) $(JAVA_SRCS) $(LIBDEPS) stamp-objlist + cd java; $(MAKE) $(FLAGS_TO_PASS) $(JAVA_FLAGS_TO_PASS) ../jc1$(exeext) + +$(GCJ).c: $(srcdir)/gcc.c + -rm -f $@ + $(LN_S) $(srcdir)/gcc.c $@ + +jvspec.o: $(srcdir)/java/jvspec.c + $(CC) -c -DWITH_THREAD_$(GCC_THREAD_FILE) \ + $(ALL_CFLAGS) $(ALL_CPPFLAGS) \ + $(INCLUDES) $(srcdir)/java/jvspec.c + +# N.B.: This is a copy of the gcc.o rule, with -DLANG_SPECIFIC_DRIVER added. +# It'd be nice if we could find an easier way to do this---rather than have +# to track changes to the toplevel gcc Makefile as well. +# We depend on $(GCJ).c last, to make it obvious where it came from. +$(GCJ).o: $(CONFIG_H) multilib.h config.status $(lang_specs_files) $(GCJ).c \ + system.h + $(CC) $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(DRIVER_DEFINES) \ + -DLANG_SPECIFIC_DRIVER \ + -c $(GCJ).c + +# Create the compiler driver for $(GCJ). +$(GCJ)$(exeext): $(GCJ).o jvspec.o version.o choose-temp.o\ + pexecute.o prefix.o mkstemp.o $(LIBDEPS) $(EXTRA_GCC_OBJS) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ $(GCJ).o jvspec.o prefix.o \ + version.o choose-temp.o pexecute.o mkstemp.o $(EXTRA_GCC_OBJS) $(LIBS) + +# Create a version of the $(GCJ) driver which calls the cross-compiler. +$(GCJ)-cross$(exeext): $(GCJ)$(exeext) + -rm -f $(GCJ)-cross$(exeext) + cp $(GCJ)$(exeext) $(GCJ)-cross$(exeext) + +# Dependencies here must be kept in sync with dependencies in Makefile.in. +jvgenmain$(exeext): $(srcdir)/java/jvgenmain.c $(srcdir)/java/mangle.c \ + $(OBSTACK) + cd java && $(MAKE) $(FLAGS_TO_PASS) $(JAVA_FLAGS_TO_PASS) ../jvgenmain$(exeext) + +# This must be kept in sync with dependencies in Makefile.in. +GCJH_SOURCES = $(srcdir)/java/gjavah.c $(srcdir)/java/jcf-io.c \ + $(srcdir)/java/zextract.c $(srcdir)/java/jcf-reader.c \ + $(srcdir)/java/jcf.h $(srcdir)/java/javaop.h \ + $(srcdir)/java/javaop.def + +gcjh$(exeext): $(GCJH_SOURCES) + cd java && $(MAKE) $(FLAGS_TO_PASS) $(JAVA_FLAGS_TO_PASS) ../gcjh$(exeext) + + + +# Build hooks: + +java.all.build: $(GCJ)$(exeext) jvgenmain$(exeext) gcjh$(exeext) +java.all.cross: $(GCJ)-cross$(exeext) jvgenmain$(exeext) gcjh$(exeext) +java.start.encap: $(GCJ)$(exeext) +java.rest.encap: jvgenmain$(exeext) gcjh$(exeext) + +java.info: + +# Install hooks: +# jc1, gcj, jvgenmain, and gcjh are installed elsewhere as part +# of $(COMPILERS). + +# Nothing to do here. +java.install-normal: + +java.install-common: + -if [ -f $(GCJ)$(exeext) ]; then \ + if [ -f $(GCJ)-cross$(exeext) ]; then \ + rm -f $(bindir)/$(JAVA_CROSS_NAME)$(exeext); \ + $(INSTALL_PROGRAM) $(GCJ)-cross$(exeext) $(bindir)/$(JAVA_CROSS_NAME)$(exeext); \ + chmod a+x $(bindir)/$(JAVA_CROSS_NAME)$(exeext); \ + else \ + rm -f $(bindir)/$(JAVA_INSTALL_NAME)$(exeext); \ + $(INSTALL_PROGRAM) $(GCJ)$(exeext) $(bindir)/$(JAVA_INSTALL_NAME)$(exeext); \ + chmod a+x $(bindir)/$(JAVA_INSTALL_NAME)$(exeext); \ + fi ; \ + fi ; \ + for tool in $(JAVA_TARGET_INDEPENDENT_BIN_TOOLS); do \ + if [ -f $$tool$(exeext) ]; then \ + rm -f $(bindir)/$$tool$(exeext); \ + $(INSTALL_PROGRAM) $$tool$(exeext) $(bindir)/$$tool$(exeext); \ + chmod a+x $(bindir)/$$tool$(exeext); \ + fi ; \ + done + +java.install-man: + +java.uninstall: + -rm -rf $(bindir)/$(JAVA_INSTALL_NAME)$(exeext) + -rm -rf $(bindir)/$(JAVA_CROSS_NAME)$(exeext) + +java.install-info: + + +# Clean hooks: +# A lot of the ancillary files are deleted by the main makefile. +# We just have to delete files specific to us. + +java.mostlyclean: + -rm -f java/*$(objext) $(DEMANGLER_PROG) +java.clean: +java.distclean: + -rm -f java/config.status java/Makefile + -rm -f java/parse.output +java.extraclean: +java.maintainer-clean: + -rm -f java/parse.h + +# Stage hooks: +# The main makefile has already created stage?/java. + +java.stage1: + -mv java/*$(objext) stage1/java +java.stage2: + -mv java/*$(objext) stage2/java +java.stage3: + -mv java/*$(objext) stage3/java +java.stage4: + -mv java/*$(objext) stage4/java + +# Maintenance hooks: + +# This target creates the files that can be rebuilt, but go in the +# distribution anyway. It then copies the files to the distdir directory. +java.distdir: + mkdir tmp/java + cd java ; $(MAKE) $(FLAGS_TO_PASS) $(JAVA_FLAGS_TO_PASS) parse.c hash.h + cd java; \ + for file in *[0-9a-zA-Z+]; do \ + ln $$file ../tmp/java >/dev/null 2>&1 || cp $$file ../tmp/java; \ + done diff --git a/gcc/java/Makefile.in b/gcc/java/Makefile.in new file mode 100644 index 00000000000..6f043dcca9c --- /dev/null +++ b/gcc/java/Makefile.in @@ -0,0 +1,258 @@ +# Makefile for GNU compiler for the Java(TM) language. +# Copyright (C) 1987, 88, 90-4, 1995, 1998 Free Software Foundation, Inc. + +#This file is part of GNU CC. + +#GNU CC 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, +#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 +#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. + +# The makefile built from this file lives in the language subdirectory. +# Its purpose is to provide support for: +# +# 1) recursion where necessary, and only then (building .o's), and +# 2) building and debugging cc1 from the language subdirectory, and +# 3) nothing else. +# +# The parent makefile handles all other chores, with help from the +# language makefile fragment, of course. +# +# The targets for external use are: +# all, TAGS, ???mostlyclean, ???clean. + +# Suppress smart makes who think they know how to automake Yacc files +.y.c: + +# Variables that exist for you to override. +# See below for how to change them for certain systems. + +ALLOCA = + +# Various ways of specifying flags for compilations: +# CFLAGS is for the user to override to, e.g., do a bootstrap with -O2. +# BOOT_CFLAGS is the value of CFLAGS to pass +# to the stage2 and stage3 compilations +# XCFLAGS is used for most compilations but not when using the GCC just built. +XCFLAGS = +CFLAGS = -g +BOOT_CFLAGS = -O $(CFLAGS) +# These exists to be overridden by the x-* and t-* files, respectively. +X_CFLAGS = +T_CFLAGS = + +X_CPPFLAGS = +T_CPPFLAGS = + +CC = @CC@ +BISON = `if [ -f ../../bison/bison ] ; then echo ../../bison/bison -L $(srcdir)/../../bison/ ; else echo bison ; fi` +BISONFLAGS = +JAVABISONFLAGS = --name-prefix=java_ +LEX = `if [ -f ../../flex/flex ] ; then echo ../../flex/flex ; else echo flex ; fi` +LEXFLAGS = +AR = ar +AR_FLAGS = rc +SHELL = /bin/sh +MAKEINFO = makeinfo +TEXI2DVI = texi2dvi + +# Define this as & to perform parallel make on a Sequent. +# Note that this has some bugs, and it seems currently necessary +# to compile all the gen* files first by hand to avoid erroneous results. +P = + +# This is used in the definition of SUBDIR_USE_ALLOCA. +# ??? Perhaps it would be better if it just looked for *gcc*. +OLDCC = cc + +# This is used instead of ALL_CFLAGS when compiling with GCC_FOR_TARGET. +# It omits XCFLAGS, and specifies -B./. +# It also specifies -B$(tooldir)/ to find as and ld for a cross compiler. +GCC_CFLAGS=$(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) + +# Tools to use when building a cross-compiler. +# These are used because `configure' appends `cross-make' +# to the makefile when making a cross-compiler. + +# We don't use cross-make. Instead we use the tools +# from the build tree, if they are available. +# program_transform_name and objdir are set by configure.in. +program_transform_name = +objdir = . + ++target=@target@ ++xmake_file=@dep_host_xmake_file@ ++tmake_file=@dep_tmake_file@ +#version=`sed -e 's/.*\"\([^ \"]*\)[ \"].*/\1/' < $(srcdir)/version.c` +#mainversion=`sed -e 's/.*\"\([0-9]*\.[0-9]*\).*/\1/' < $(srcdir)/version.c` + +# Directory where sources are, from where we are. +srcdir = @srcdir@ +VPATH = @srcdir@ + +# Additional system libraries to link with. +CLIB= + +# Change this to a null string if obstacks are installed in the +# system library. +OBSTACK=obstack.o + +# Choose the real default target. +ALL=all + +# End of variables for you to override. + +# Definition of `all' is here so that new rules inserted by sed +# do not specify the default target. +all: all.indirect + +# This tells GNU Make version 3 not to put all variables in the environment. +.NOEXPORT: + +# sed inserts variable overrides after the following line. +####target overrides +@target_overrides@ +####host overrides +@host_overrides@ +####cross overrides +@cross_overrides@ +####build overrides +@build_overrides@ +####site overrides + +# Now figure out from those variables how to compile and link. + +all.indirect: Makefile ../jc1$(exeext) ../jcf-dump$(exeext) \ + ../jvgenmain$(exeext) ../gcjh$(exeext) ../jv-scan$(exeext) + +# IN_GCC tells obstack.h that we are using gcc's file. +INTERNAL_CFLAGS = $(CROSS) -DIN_GCC @extra_c_flags@ + +# This is the variable actually used when we compile. +ALL_CFLAGS = $(INTERNAL_CFLAGS) $(X_CFLAGS) $(T_CFLAGS) $(CFLAGS) $(XCFLAGS) + +# Likewise. +ALL_CPPFLAGS = $(CPPFLAGS) $(X_CPPFLAGS) $(T_CPPFLAGS) + +# Even if ALLOCA is set, don't use it if compiling with GCC. + +SUBDIR_OBSTACK = `if [ x$(OBSTACK) != x ]; then echo ../$(OBSTACK); else true; fi` +SUBDIR_USE_ALLOCA = `case "${CC}" in "${OLDCC}") if [ x$(ALLOCA) != x ]; then echo ../$(ALLOCA); else true; fi ;; esac` +SUBDIR_MALLOC = `if [ x$(MALLOC) != x ]; then echo ../$(MALLOC); else true; fi` + +# How to link with both our special library facilities +# and the system's installed libraries. +LIBS = $(SUBDIR_OBSTACK) $(SUBDIR_USE_ALLOCA) $(SUBDIR_MALLOC) $(CLIB) + +# Specify the directories to be searched for header files. +# Both . and srcdir are used, in that order, +# so that tm.h and config.h will be found in the compilation +# subdirectory rather than in the source directory. +INCLUDES = -I. -I.. -I$(srcdir) -I$(srcdir)/.. -I$(srcdir)/../config + +# Always use -I$(srcdir)/config when compiling. +.c.o: + $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $< + +# This tells GNU make version 3 not to export all the variables +# defined in this file into the environment. +.NOEXPORT: + +# Lists of files for various purposes. + +# Language-specific object files for Gcc/Java: + +# Remember to keep this list in sync with JAVA_SRCS in Make-lang.in!!! +# +JAVA_OBJS = parse.o class.o decl.o expr.o constants.o lang.o typeck.o \ + except.o verify.o zextract.o jcf-io.o jcf-parse.o mangle.o jcf-write.o \ + buffer.o + +JAVA_OBJS_LITE = parse-scan.o jv-scan.o + +# Language-independent object files. +OBJS = `cat ../stamp-objlist` +OBJDEPS = ../stamp-objlist + +compiler: ../jc1$(exeext) ../jv-scan$(exeext) +../jc1$(exeext): $(P) $(JAVA_OBJS) $(OBJDEPS) $(LIBDEPS) + rm -f ../jc1$(exeext) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \ + $(JAVA_OBJS) $(OBJS) $(LIBS) +../jv-scan$(exeext): $(P) $(JAVA_OBJS_LITE) $(OBJDEPS) $(LIBDEPS) + rm -f ../jv-scan$(exeext) + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ \ + $(JAVA_OBJS_LITE) $(LIBS) + +../jcf-dump$(exeext): jcf-dump.o jcf-io.o zextract.o + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ jcf-dump.o jcf-io.o zextract.o + +# Dependencies here must be kept in sync with dependencies in Make-lang.in. +../jvgenmain$(exeext): jvgenmain.o mangle.o + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ jvgenmain.o mangle.o ../obstack.o + +../gcjh$(exeext): gjavah.o jcf-io.o zextract.o + $(CC) $(ALL_CFLAGS) $(LDFLAGS) -o $@ gjavah.o jcf-io.o zextract.o + +Makefile: $(srcdir)/Makefile.in $(srcdir)/../configure + cd ..; $(SHELL) config.status + +native: config.status ../jc1$(exeext) + +# Compiling object files from source files. + +PARSE_H = $(srcdir)/parse.h +PARSE_C = $(srcdir)/parse.c +PARSE_SCAN_C = $(srcdir)/parse-scan.c + +$(PARSE_H): $(PARSE_C) +$(PARSE_C): $(srcdir)/parse.y $(srcdir)/lex.c $(PARSE_H) $(srcdir)/lex.h + $(BISON) -t -v $(BISONFLAGS) $(JAVABISONFLAGS) -o $(PARSE_C) \ + $(srcdir)/parse.y +$(PARSE_SCAN_C): $(srcdir)/parse-scan.y $(srcdir)/lex.c $(PARSE_H) \ + $(srcdir)/lex.h + $(BISON) -t -v $(BISONFLAGS) -o $(PARSE_SCAN_C) $(srcdir)/parse-scan.y + +lex.c: keyword.h lex.h + +keyword.h: keyword.gperf + gperf -p -t -j1 -i 1 -g -o -N java_keyword -k1,3,$$ \ + keyword.gperf > keyword.h + +# These exist for maintenance purposes. + +# Update the tags table. +TAGS: force + cd $(srcdir) ; \ + etags *.c *.h ; \ + echo 'l' | tr 'l' '\f' >> TAGS ; \ + echo 'parse.y,0' >> TAGS ; \ + etags -a ../*.h ../*.c; + +.PHONY: TAGS + +mostlyclean: + rm -f *.o + +clean: mostlyclean + rm -f parse.c + +force: + +parse.o: $(PARSE_C) jcf-reader.c +jcf-dump.o: jcf-reader.c jcf.h javaop.h javaop.def +gjavah.o: jcf-reader.c jcf.h javaop.h diff --git a/gcc/java/buffer.c b/gcc/java/buffer.c new file mode 100644 index 00000000000..cea7899973b --- /dev/null +++ b/gcc/java/buffer.c @@ -0,0 +1,50 @@ +/* A "buffer" utility type. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Written by Per Bothner , July 1998. */ + +#include "gansidecl.h" +#include "buffer.h" + +/* Grow BUFP so there is room for at least SIZE more bytes. */ + +void +buffer_grow (bufp, size) + struct buffer *bufp; + int size; +{ + if (bufp->limit - bufp->ptr >= size) + return; + if (bufp->data == 0) + { + if (size < 120) + size = 120; + bufp->data = (unsigned char*) xmalloc (size); + bufp->ptr = bufp->data; + } + else + { + int index = bufp->ptr - bufp->data; + size += 2 * (bufp->limit - bufp->data); + bufp->data = (unsigned char *) xrealloc (bufp->data, size); + bufp->ptr = bufp->data + index; + } + bufp->limit = bufp->data + size; +} diff --git a/gcc/java/buffer.h b/gcc/java/buffer.h new file mode 100644 index 00000000000..aa63840d759 --- /dev/null +++ b/gcc/java/buffer.h @@ -0,0 +1,43 @@ +/* A "buffer" utility type. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Written by Per Bothner , July 1998. */ + +/* A simple data structure for an expandable buffer. */ + +struct buffer +{ + /* The start of the actual data buffer. */ + unsigned char *data; + + /* Where to write next in the buffer. */ + unsigned char *ptr; + + /* The end of the allocated data buffer. */ + unsigned char *limit; +}; + +#define NULL_BUFFER { (void*) 0, (void*) 0, (void*) 0 } + +#define BUFFER_LENGTH(BUFP) ((BUFP)->ptr - (BUFP)->data) + +#define BUFFER_RESET(BUFP) ((BUFP)->ptr = (BUFP)->data) + +extern void buffer_grow PROTO ((struct buffer*, int)); diff --git a/gcc/java/class.c b/gcc/java/class.c new file mode 100644 index 00000000000..9dc49dcbeec --- /dev/null +++ b/gcc/java/class.c @@ -0,0 +1,1601 @@ +/* Functions related to building classes and their related objects. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Written by Per Bothner */ + +#include +#include "config.h" +#include "tree.h" +#include "rtl.h" +#include "java-tree.h" +#include "jcf.h" +#include "obstack.h" + +static tree mangle_class_field PROTO ((tree class)); + +static rtx registerClass_libfunc; + +extern struct obstack permanent_obstack; +extern struct obstack temporary_obstack; + +/* Return an IDENTIFIER_NODE the same as (OLD_NAME, OLD_LENGTH). + except that characters matching OLD_CHAR are substituted by NEW_CHAR. + Also, PREFIX is prepended, and SUFFIX is appended. */ + +tree +ident_subst (old_name, old_length, prefix, old_char, new_char, suffix) + const char* old_name; + int old_length; + const char *prefix; + int old_char; + int new_char; + const char *suffix; +{ + int prefix_len = strlen (prefix); + int suffix_len = strlen (suffix); + int i = prefix_len + old_length + suffix_len + 1; +#ifdef __GNUC__ + char buffer[i]; +#else + char *buffer = (char *)alloca (i); +#endif + strcpy (buffer, prefix); + for (i = 0; i < old_length; i++) + { + char ch = old_name[i]; + if (ch == old_char) + ch = new_char; + buffer[prefix_len + i] = ch; + } + strcpy (buffer + prefix_len + old_length, suffix); + return get_identifier (buffer); +} + +/* Return an IDENTIFIER_NODE the same as OLD_ID, + except that characters matching OLD_CHAR are substituted by NEW_CHAR. + Also, PREFIX is prepended, and SUFFIX is appended. */ + +tree +identifier_subst (old_id, prefix, old_char, new_char, suffix) + const tree old_id; + const char *prefix; + int old_char; + int new_char; + const char *suffix; +{ + return ident_subst (IDENTIFIER_POINTER (old_id), IDENTIFIER_LENGTH (old_id), + prefix, old_char, new_char, suffix); +} + +/* Generate a valid C identifier from the name of the class TYPE, + prefixed by PREFIX. */ + +tree +mangled_classname (prefix, type) + char *prefix; + tree type; +{ + tree ident = TYPE_NAME (type); + if (TREE_CODE (ident) != IDENTIFIER_NODE) + ident = DECL_NAME (ident); + return identifier_subst (ident, prefix, '/', '_', ""); +} + +tree +make_class () +{ + tree type; + push_obstacks (&permanent_obstack, &permanent_obstack); + type = make_node (RECORD_TYPE); +#ifdef JAVA_USE_HANDLES + tree field1 = build_decl (FIELD_DECL, get_identifier ("obj"), + build_pointer_type (type)); + tree field2 = build_decl (FIELD_DECL, get_identifier ("methods"), + methodtable_ptr_type); + tree handle_type = make_node (RECORD_TYPE); + TREE_CHAIN (field1) = field2; + TYPE_FIELDS (handle_type) = field1; + TYPE_BINFO (type) = make_tree_vec (7); + TYPE_BINFO (handle_type) = make_tree_vec (7); + BINFO_HANDLE (TYPE_BINFO (handle_type)) = type; + BINFO_HANDLE (TYPE_BINFO (type)) = handle_type; +#else + TYPE_BINFO (type) = make_tree_vec (6); +#endif + CLASS_P (type) = 1; + pop_obstacks (); + + return type; +} + +/* Given a fully-qualified classname in NAME (whose length is NAME_LENGTH), + and where each of the constituents is separated by '/', + return a corresponding IDENTIFIER_NODE, except using '.' as separator. */ + +tree +unmangle_classname (name, name_length) + const char *name; int name_length; +{ + return ident_subst (name, name_length, "", '/', '.', ""); +} + +tree +push_class (class_type, class_name) + tree class_type, class_name; +{ + tree decl, signature; + char *save_input_filename = input_filename; + int save_lineno = lineno; + tree source_name = identifier_subst (class_name, "", '.', '/', ".java"); + push_obstacks (&permanent_obstack, &permanent_obstack); + input_filename = IDENTIFIER_POINTER (source_name); + lineno = 0; + decl = build_decl (TYPE_DECL, class_name, class_type); + input_filename = save_input_filename; + lineno = save_lineno; + signature = identifier_subst (class_name, "L", '.', '/', ";"); + IDENTIFIER_SIGNATURE_TYPE (signature) = class_type; + + /* Setting DECL_ARTIFICAL forces dbxout.c to specific the type is + both a typedef and in the struct name-space. We may want to re-visit + this later, but for now it reduces the changes needed for gdb. */ + DECL_ARTIFICIAL (decl) = 1; + + pushdecl_top_level (decl); +#ifdef JAVA_USE_HANDLES + { + tree handle_name = identifier_subst (class_name, + "Handle$", '.', '.', ""); + tree handle_decl = build_decl (TYPE_DECL, handle_name, + CLASS_TO_HANDLE_TYPE (class_type)); + pushdecl (handle_decl); + } +#endif + + pop_obstacks (); + return decl; +} + +/* Finds the (global) class named NAME. Creates the class if not found. + Also creates associated TYPE_DECL. + Does not check if the class actually exists, load the class, + fill in field or methods, or do layout_type. */ + +tree +lookup_class (name) + tree name; +{ + tree decl = IDENTIFIER_CLASS_VALUE (name); + if (decl == NULL_TREE) + decl = push_class (make_class (), name); + return TREE_TYPE (decl); +} + +void +set_super_info (access_flags, this_class, super_class, interfaces_count) + int access_flags; + tree this_class; + tree super_class; + int interfaces_count; +{ + int total_supers = interfaces_count; + tree class_decl = TYPE_NAME (this_class); + if (super_class) + total_supers++; + + push_obstacks (&permanent_obstack, &permanent_obstack); + TYPE_BINFO_BASETYPES (this_class) = make_tree_vec (total_supers); + if (super_class) + { + tree super_binfo = make_tree_vec (6); + BINFO_TYPE (super_binfo) = super_class; + BINFO_OFFSET (super_binfo) = integer_zero_node; + TREE_VIA_PUBLIC (super_binfo) = 1; + TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO (this_class)), 0) + = super_binfo; + CLASS_HAS_SUPER (this_class) = 1; + } + pop_obstacks (); + + if (access_flags & ACC_PUBLIC) CLASS_PUBLIC (class_decl) = 1; + if (access_flags & ACC_FINAL) CLASS_FINAL (class_decl) = 1; + if (access_flags & ACC_SUPER) CLASS_SUPER (class_decl) = 1; + if (access_flags & ACC_INTERFACE) CLASS_INTERFACE (class_decl) = 1; + if (access_flags & ACC_ABSTRACT) CLASS_ABSTRACT (class_decl) = 1; +} + +/* Return length of inheritance chain of CLAS, where java.lang.Object is 0, + direct sub-classes of Object are 1, and so on. */ + +int +class_depth (clas) + tree clas; +{ + int depth = 0; + if (! CLASS_LOADED_P (clas)) + load_class (clas, 1); + while (clas != object_type_node) + { + depth++; + clas = TYPE_BINFO_BASETYPE (clas, 0); + } + return depth; +} + +/* Return true iff TYPE2 is an interface that extends interface TYPE1 */ + +int +interface_of_p (type1, type2) + tree type1, type2; +{ + int n, i; + tree basetype_vec; + + if (!(basetype_vec = TYPE_BINFO_BASETYPES (type2))) + return 0; + n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; i < n; i++) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + if (vec_elt && BINFO_TYPE (vec_elt) == type1) + return 1; + } + for (i = 0; i < n; i++) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + if (vec_elt && BINFO_TYPE (vec_elt) + && interface_of_p (type1, BINFO_TYPE (vec_elt))) + return 1; + } + return 0; +} + +/* Return true iff TYPE1 inherits from TYPE2. */ + +int +inherits_from_p (type1, type2) + tree type1, type2; +{ + while (type1 != NULL_TREE && TREE_CODE (type1) == RECORD_TYPE) + { + if (type1 == type2) + return 1; + type1 = CLASSTYPE_SUPER (type1); + } + return 0; +} + +static void +add_interface_do (basetype_vec, interface_class, i) + tree basetype_vec, interface_class; + int i; +{ + tree interface_binfo = make_tree_vec (6); + BINFO_TYPE (interface_binfo) = interface_class; + BINFO_OFFSET (interface_binfo) = integer_zero_node; + TREE_VIA_VIRTUAL (interface_binfo) = 1; + TREE_VIA_PUBLIC (interface_binfo) = 1; + TREE_VEC_ELT (basetype_vec, i) = interface_binfo; +} + +/* Add INTERFACE_CLASS to THIS_CLASS iff INTERFACE_CLASS can't be + found in THIS_CLASS. Returns NULL_TREE upon success, INTERFACE_CLASS + if attempt is made to add it twice. */ + +tree +maybe_add_interface (this_class, interface_class) + tree this_class, interface_class; +{ + tree basetype_vec = TYPE_BINFO_BASETYPES (this_class); + tree interface_binfo = make_tree_vec (6); + int i; + int n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; ; i++) + { + if (i >= n) + { + error ("internal error - too many interface type"); + return NULL_TREE; + } + else if (TREE_VEC_ELT (basetype_vec, i) == NULL_TREE) + break; + else if (BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i)) == interface_class) + return interface_class; + } + add_interface_do (basetype_vec, interface_class, i); + return NULL_TREE; +} + +/* Add the INTERFACE_CLASS as one of the interfaces of THIS_CLASS. */ + +void +add_interface (this_class, interface_class) + tree this_class, interface_class; +{ + tree basetype_vec = TYPE_BINFO_BASETYPES (this_class); + int i; + int n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; ; i++) + { + if (i >= n) + { + error ("internal error - too many interface type"); + return; + } + else if (TREE_VEC_ELT (basetype_vec, i) == NULL_TREE) + break; + } + add_interface_do (basetype_vec, interface_class, i); +} + +/* Return the address of a pointer to the first FUNCTION_DECL + in the list (*LIST) whose DECL_NAME is NAME. */ + +static tree * +find_named_method (list, name) + tree *list; + tree name; +{ + while (*list && DECL_NAME (*list) != name) + list = &TREE_CHAIN (*list); + return list; +} + +tree +build_java_method_type (fntype, this_class, access_flags) + tree fntype; + tree this_class; + int access_flags; +{ + if (access_flags & ACC_STATIC) + return fntype; + return build_method_type (CLASS_TO_HANDLE_TYPE (this_class), fntype); +} + +tree +add_method_1 (handle_class, access_flags, name, function_type) + tree handle_class; + int access_flags; + tree name; + tree function_type; +{ + tree method_type, fndecl; + push_obstacks (&permanent_obstack, &permanent_obstack); + + method_type = build_java_method_type (function_type, + handle_class, access_flags); + + fndecl = build_decl (FUNCTION_DECL, name, method_type); + DECL_CONTEXT (fndecl) = handle_class; + + DECL_LANG_SPECIFIC (fndecl) + = (struct lang_decl *) permalloc (sizeof (struct lang_decl)); + bzero (DECL_LANG_SPECIFIC (fndecl), sizeof (struct lang_decl)); + + TREE_CHAIN (fndecl) = TYPE_METHODS (handle_class); + TYPE_METHODS (handle_class) = fndecl; + pop_obstacks (); + + if (access_flags & ACC_PUBLIC) METHOD_PUBLIC (fndecl) = 1; + if (access_flags & ACC_PROTECTED) METHOD_PROTECTED (fndecl) = 1; + if (access_flags & ACC_PRIVATE) METHOD_PRIVATE (fndecl) = 1; + if (access_flags & ACC_NATIVE) METHOD_NATIVE (fndecl) = 1; + if (access_flags & ACC_STATIC) METHOD_STATIC (fndecl) = 1; + if (access_flags & ACC_FINAL) METHOD_FINAL (fndecl) = 1; + if (access_flags & ACC_SYNCHRONIZED) METHOD_SYNCHRONIZED (fndecl) = 1; + if (access_flags & ACC_ABSTRACT) METHOD_ABSTRACT (fndecl) = 1; + if (access_flags & ACC_TRANSIENT) METHOD_TRANSIENT (fndecl) = 1; + return fndecl; +} + +/* Add a method to THIS_CLASS. + The method's name is NAME. + Its signature (mangled type) is METHOD_SIG (an IDENTIFIER_NODE). */ + +tree +add_method (this_class, access_flags, name, method_sig) + tree this_class; + int access_flags; + tree name; + tree method_sig; +{ + tree handle_class = CLASS_TO_HANDLE_TYPE (this_class); + tree function_type, method_type, fndecl; + unsigned char *sig = (unsigned char*)IDENTIFIER_POINTER (method_sig); + push_obstacks (&permanent_obstack, &permanent_obstack); + if (sig[0] != '(') + fatal ("bad method signature"); + function_type = get_type_from_signature (method_sig); + fndecl = add_method_1 (handle_class, access_flags, name, function_type); + set_java_signature (TREE_TYPE (fndecl), method_sig); + pop_obstacks (); + return fndecl; +} + +tree +add_field (class, name, field_type, flags) + tree class; + tree name; + tree field_type; + int flags; +{ + int is_static = (flags & ACC_STATIC) != 0; + tree field; + /* Push the obstack of field_type ? FIXME */ + push_obstacks (&permanent_obstack, &permanent_obstack); +#if ! JAVA_PROMOTE_TO_INT + if (TREE_CODE (field_type) == RECORD_TYPE) +#endif + field_type = promote_type (field_type); + field = build_decl (is_static ? VAR_DECL : FIELD_DECL, name, field_type); + pop_obstacks (); + TREE_CHAIN (field) = TYPE_FIELDS (class); + TYPE_FIELDS (class) = field; + DECL_CONTEXT (field) = class; + + if (flags & ACC_PUBLIC) FIELD_PUBLIC (field) = 1; + if (flags & ACC_PROTECTED) FIELD_PROTECTED (field) = 1; + if (flags & ACC_PRIVATE) FIELD_PRIVATE (field) = 1; + if (flags & ACC_FINAL) FIELD_FINAL (field) = 1; + if (flags & ACC_VOLATILE) FIELD_VOLATILE (field) = 1; + if (flags & ACC_TRANSIENT) FIELD_TRANSIENT (field) = 1; + if (is_static) + { + FIELD_STATIC (field) = 1; + if (! FIELD_PRIVATE (field) || FIELD_PROTECTED (field)) + TREE_PUBLIC (field) = 1; + } + return field; +} + +/* Associate a constant value CONSTANT with VAR_DECL FIELD. */ + +void +set_constant_value (field, constant) + tree field, constant; +{ + if (field == NULL_TREE) + warning ("misplaced ConstantValue attribute (not in any field)"); + else if (DECL_INITIAL (field) != NULL_TREE) + warning ("duplicate ConstanValue atribute for field '%s'", + IDENTIFIER_POINTER (DECL_NAME (field))); + else + DECL_INITIAL (field) = constant; +} + +/* Count the number of Unicode chars encoded in a given Ut8 string. */ + +int +strLengthUtf8 (str, len) + char *str; + int len; +{ + register unsigned char* ptr = (unsigned char*) str; + register unsigned char *limit = ptr + len; + int str_length = 0; + for (; ptr < limit; str_length++) { + if (UTF8_GET (ptr, limit) < 0) + return -1; + } + return str_length; +} + + +/* Calculate a hash value for a string encoded in Utf8 format. + * This returns the same hash value as specified for java.lang.String.hashCode. + */ + +int32 +hashUtf8String (str, len) + char *str; + int len; +{ + register unsigned char* ptr = (unsigned char*) str; + register unsigned char *limit = ptr + len; + int32 hash = 0; + for (; ptr < limit;) + { + int ch = UTF8_GET (ptr, limit); + /* Updated specification from + http://www.javasoft.com/docs/books/jls/clarify.html. */ + hash = (31 * hash) + ch; + } + return hash; +} + +tree utf8_decl_list = NULL_TREE; + +tree +build_utf8_ref (name) + tree name; +{ + char* name_ptr = IDENTIFIER_POINTER(name); + int name_len = IDENTIFIER_LENGTH(name); + char buf[60]; + char *buf_ptr; + tree ctype, field, str_type, cinit, string; + static int utf8_count = 0; + int name_hash; + tree ref = IDENTIFIER_UTF8_REF (name); + tree decl; + if (ref != NULL_TREE) + return ref; + + push_obstacks (&permanent_obstack, &permanent_obstack); + ctype = make_node (RECORD_TYPE); + str_type = build_prim_array_type (unsigned_byte_type_node, + name_len + 1); /* Allow for final '\0'. */ + PUSH_FIELD (ctype, field, "hash", unsigned_short_type_node); + PUSH_FIELD (ctype, field, "length", unsigned_short_type_node); + PUSH_FIELD (ctype, field, "data", str_type); + FINISH_RECORD (ctype); + START_RECORD_CONSTRUCTOR (cinit, ctype); + name_hash = hashUtf8String (name_ptr, name_len) & 0xFFFF; + PUSH_FIELD_VALUE (cinit, "hash", build_int_2 (name_hash, 0)); + PUSH_FIELD_VALUE (cinit, "length", build_int_2 (name_len, 0)); + string = build_string (name_len, name_ptr); + TREE_TYPE (string) = str_type; + PUSH_FIELD_VALUE (cinit, "data", string); + FINISH_RECORD_CONSTRUCTOR (cinit); + + /* Build a unique identifier based on buf. */ + sprintf(buf, "_Utf%d", ++utf8_count); + buf_ptr = &buf[strlen (buf)]; + while (--name_len >= 0) + { + char c = *name_ptr++; + if (c & 0x80) + continue; + if (!isalpha(c) && !isdigit(c)) + c = '_'; + *buf_ptr++ = c; + if (buf_ptr >= buf + 50) + break; + } + *buf_ptr = '\0'; + + decl = build_decl (VAR_DECL, get_identifier (buf), utf8const_type); + /* FIXME get some way to force this into .text, not .data. */ + TREE_STATIC (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_IGNORED_P (decl) = 1; + TREE_READONLY (decl) = 1; + DECL_INITIAL (decl) = cinit; + TREE_CHAIN (decl) = utf8_decl_list; + layout_decl (decl, 0); + pushdecl (decl); + rest_of_decl_compilation (decl, (char*) 0, global_bindings_p (), 0); + utf8_decl_list = decl; + make_decl_rtl (decl, (char*) 0, 1); + ref = build1 (ADDR_EXPR, utf8const_ptr_type, decl); + IDENTIFIER_UTF8_REF (name) = ref; + pop_obstacks (); + return ref; +} + +/* Build a reference to the class TYPE. + Also handles primitive types and array types. */ + +tree +build_class_ref (type) + tree type; +{ + int is_compiled = is_compiled_class (type); + if (is_compiled) + { + tree ref, decl_name, decl; + if (TREE_CODE (type) == POINTER_TYPE) + type = TREE_TYPE (type); + if (TREE_CODE (type) == RECORD_TYPE) + { + if (TYPE_SIZE (type) == error_mark_node) + return null_pointer_node; + decl_name = identifier_subst (DECL_NAME (TYPE_NAME (type)), + "", '/', '/', ".class"); + decl = IDENTIFIER_GLOBAL_VALUE (decl_name); + if (decl == NULL_TREE) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = build_decl (VAR_DECL, decl_name, class_type_node); + DECL_SIZE (decl) = TYPE_SIZE (class_type_node); + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 1; + DECL_IGNORED_P (decl) = 1; + DECL_ARTIFICIAL (decl) = 1; + DECL_ASSEMBLER_NAME (decl) = mangle_class_field (type); + make_decl_rtl (decl, NULL, 1); + pushdecl_top_level (decl); + if (is_compiled == 1) + DECL_EXTERNAL (decl) = 1; + pop_obstacks (); + } + } + else + { + char *name; + char buffer[20]; + decl_name = TYPE_NAME (type); + if (TREE_CODE (decl_name) == TYPE_DECL) + decl_name = DECL_NAME (decl_name); + name = IDENTIFIER_POINTER (decl_name); + if (strncmp (name, "promoted_", 9) == 0) + name += 9; + sprintf (buffer, "%sClass", name); + decl_name = get_identifier (buffer); + decl = IDENTIFIER_GLOBAL_VALUE (decl_name); + if (decl == NULL_TREE) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = build_decl (VAR_DECL, decl_name, class_type_node); + TREE_STATIC (decl) = 1; + TREE_PUBLIC (decl) = 1; + make_decl_rtl (decl, NULL, 1); + pushdecl_top_level (decl); + if (is_compiled == 1) + DECL_EXTERNAL (decl) = 1; + pop_obstacks (); + } + } + + ref = build1 (ADDR_EXPR, class_ptr_type, decl); + return ref; + } + else + { + int index; + tree cl; + push_obstacks (&permanent_obstack, &permanent_obstack); + index = alloc_class_constant (type); + cl = build_ref_from_constant_pool (index); + TREE_TYPE (cl) = promote_type (class_ptr_type); + pop_obstacks (); + return cl; + } +} + +tree +build_static_field_ref (fdecl) + tree fdecl; +{ + tree fclass = DECL_CONTEXT (fdecl); + int is_compiled = is_compiled_class (fclass); + if (is_compiled) + { + if (DECL_RTL (fdecl) == 0) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + make_decl_rtl (fdecl, NULL, 1); + pop_obstacks (); + if (is_compiled == 1) + DECL_EXTERNAL (fdecl) = 1; + } + return fdecl; + } + else + { + /* Compile as: + * *(FTYPE*)build_class_ref(FCLASS)->fields[INDEX].info.addr + */ + static tree fields_ident = NULL_TREE; + static tree info_ident = NULL_TREE; + tree ref = build_class_ref (fclass); + tree fld; + int field_index = 0; + ref = build1 (INDIRECT_REF, class_type_node, ref); + if (fields_ident == NULL_TREE) + fields_ident = get_identifier ("fields"); + if (info_ident == NULL_TREE) + info_ident = get_identifier ("info"); + ref = build (COMPONENT_REF, field_ptr_type_node, ref, + lookup_field (&class_type_node, fields_ident)); + + for (fld = TYPE_FIELDS (fclass); ; fld = TREE_CHAIN (fld)) + { + if (fld == fdecl) + break; + if (fld == NULL_TREE) + fatal ("field '%s' not found in class", + IDENTIFIER_POINTER (DECL_NAME (fdecl))); + if (FIELD_STATIC (fld)) + field_index++; + } + field_index *= int_size_in_bytes (field_type_node); + ref = fold (build (PLUS_EXPR, field_ptr_type_node, + ref, build_int_2 (field_index, 0))); + ref = build1 (INDIRECT_REF, field_type_node, ref); + ref = build (COMPONENT_REF, field_info_union_node, + ref, lookup_field (&field_type_node, info_ident)); + ref = build (COMPONENT_REF, ptr_type_node, + ref, TREE_CHAIN (TYPE_FIELDS (field_info_union_node))); + return fold (build1 (INDIRECT_REF, TREE_TYPE(fdecl), ref)); + } +} + +int +get_access_flags_from_decl (decl) + tree decl; +{ + int access_flags = 0; + if (TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL) + { + if (FIELD_STATIC (decl)) + access_flags |= ACC_STATIC; + if (FIELD_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (FIELD_PROTECTED (decl)) + access_flags |= ACC_PROTECTED; + if (FIELD_PRIVATE (decl)) + access_flags |= ACC_PRIVATE; + if (FIELD_FINAL (decl)) + access_flags |= ACC_FINAL; + if (FIELD_VOLATILE (decl)) + access_flags |= ACC_VOLATILE; + if (FIELD_TRANSIENT (decl)) + access_flags |= ACC_TRANSIENT; + return access_flags; + } + if (TREE_CODE (decl) == TYPE_DECL) + { + if (CLASS_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (CLASS_FINAL (decl)) + access_flags |= ACC_FINAL; + if (CLASS_SUPER (decl)) + access_flags |= ACC_SUPER; + if (CLASS_INTERFACE (decl)) + access_flags |= ACC_INTERFACE; + if (CLASS_ABSTRACT (decl)) + access_flags |= ACC_ABSTRACT; + return access_flags; + } + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (METHOD_PUBLIC (decl)) + access_flags |= ACC_PUBLIC; + if (METHOD_PRIVATE (decl)) + access_flags |= ACC_PRIVATE; + if (METHOD_PROTECTED (decl)) + access_flags |= ACC_PROTECTED; + if (METHOD_STATIC (decl)) + access_flags |= ACC_STATIC; + if (METHOD_FINAL (decl)) + access_flags |= ACC_FINAL; + if (METHOD_SYNCHRONIZED (decl)) + access_flags |= ACC_SYNCHRONIZED; + if (METHOD_NATIVE (decl)) + access_flags |= ACC_NATIVE; + if (METHOD_ABSTRACT (decl)) + access_flags |= ACC_ABSTRACT; + if (METHOD_TRANSIENT (decl)) + access_flags |= ACC_TRANSIENT; + return access_flags; + } + abort (); +} + +tree +make_field_value (tree fdecl) +{ + tree finit, info; + int bsize, flags; + tree type = TREE_TYPE (fdecl); + int resolved = is_compiled_class (type); + START_RECORD_CONSTRUCTOR (finit, field_type_node); + PUSH_FIELD_VALUE (finit, "name", build_utf8_ref (DECL_NAME (fdecl))); + if (resolved) + type = build_class_ref (type); + else + type = build_utf8_ref (build_java_signature (type)); + PUSH_FIELD_VALUE (finit, "type", type); + flags = get_access_flags_from_decl (fdecl); + if (! resolved) + flags |= 0x8000 /* FIELD_UNRESOLVED_FLAG */; + PUSH_FIELD_VALUE (finit, "accflags", build_int_2 (flags, 0)); + bsize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (fdecl))) / BITS_PER_UNIT; + PUSH_FIELD_VALUE (finit, "bsize", build_int_2 (bsize, 0)); + if (FIELD_STATIC (fdecl)) + { + tree cfield = TREE_CHAIN (TYPE_FIELDS(field_info_union_node)); + tree faddr = build_address_of (build_static_field_ref (fdecl)); + info = build (CONSTRUCTOR, field_info_union_node, NULL_TREE, + build_tree_list (cfield, faddr)); + } + else + { + int boffset + = TREE_INT_CST_LOW (DECL_FIELD_BITPOS (fdecl)) / BITS_PER_UNIT; + info = build (CONSTRUCTOR, field_info_union_node, NULL_TREE, + build_tree_list (TYPE_FIELDS(field_info_union_node), + build_int_2 (boffset, 0))); + } + PUSH_FIELD_VALUE (finit, "info", info); + + FINISH_RECORD_CONSTRUCTOR (finit); + return finit; +} + +tree +make_method_value (mdecl, this_class_addr) + tree mdecl; + tree this_class_addr; +{ + tree minit; + tree code; +#define ACC_TRANSLATED 0x4000 + int accflags = get_access_flags_from_decl (mdecl) | ACC_TRANSLATED; + code = null_pointer_node; + if (DECL_RTL (mdecl)) + code = build1 (ADDR_EXPR, nativecode_ptr_type_node, mdecl); + START_RECORD_CONSTRUCTOR (minit, method_type_node); + PUSH_FIELD_VALUE (minit, "name", + build_utf8_ref (DECL_CONSTRUCTOR_P (mdecl) ? + init_identifier_node + : DECL_NAME (mdecl))); + PUSH_FIELD_VALUE (minit, "signature", + build_utf8_ref (build_java_signature (TREE_TYPE (mdecl)))); + PUSH_FIELD_VALUE (minit, "accflags", build_int_2 (accflags, 0)); + PUSH_FIELD_VALUE (minit, "ncode", code); + FINISH_RECORD_CONSTRUCTOR (minit); + return minit; +} + +tree +get_dispatch_vector (type) + tree type; +{ + tree vtable = TYPE_VTABLE (type); + if (vtable == NULL) + { + int i; + tree method; + tree super = CLASSTYPE_SUPER (type); + int nvirtuals = TREE_INT_CST_LOW (TYPE_NVIRTUALS (type)); + vtable = make_tree_vec (nvirtuals); + TYPE_VTABLE (type) = vtable; + if (super != NULL_TREE) + { + tree super_vtable = get_dispatch_vector (super); + for ( i = TREE_INT_CST_LOW (TYPE_NVIRTUALS (super)); --i >= 0; ) + TREE_VEC_ELT (vtable, i) = TREE_VEC_ELT (super_vtable, i); + } + for (method = TYPE_METHODS (type); method != NULL_TREE; + method = TREE_CHAIN (method)) + { + if (DECL_VINDEX (method) != NULL_TREE + && TREE_CODE (DECL_VINDEX (method)) == INTEGER_CST) + { + TREE_VEC_ELT (vtable, TREE_INT_CST_LOW (DECL_VINDEX (method))) + = method; + } + } + } + return vtable; +} + +tree +get_dispatch_table (type, this_class_addr) + tree type, this_class_addr; +{ + tree vtable = get_dispatch_vector (type); + int i; + tree list = NULL_TREE; + int nvirtuals = TREE_VEC_LENGTH (vtable); + for (i = nvirtuals; --i >= 0; ) + { + tree method = TREE_VEC_ELT (vtable, i); + if (METHOD_ABSTRACT (method)) + warning_with_decl (method, "abstract method in non-abstract class"); + if (DECL_RTL (method) == 0) + make_decl_rtl (method, NULL, 1); + list = tree_cons (NULL_TREE /*DECL_VINDEX (method) + 2*/, + build1 (ADDR_EXPR, nativecode_ptr_type_node, method), + list); + } + /* Dummy entry for compatibility with G++ -fvtable-thunks. */ + list = tree_cons (integer_zero_node, null_pointer_node, list); + list = tree_cons (integer_zero_node, this_class_addr, list); + return build (CONSTRUCTOR, build_prim_array_type (nativecode_ptr_type_node, + nvirtuals + 2), + NULL_TREE, list); +} + +void +make_class_data (type) + tree type; +{ + tree decl, cons, temp; + tree field, fields_decl; + tree static_fields = NULL_TREE; + tree instance_fields = NULL_TREE; + HOST_WIDE_INT static_field_count = 0; + HOST_WIDE_INT instance_field_count = 0; + HOST_WIDE_INT field_count; + tree field_array_type; + tree method; + tree methods = NULL_TREE; + tree dtable_decl = NULL_TREE; + HOST_WIDE_INT method_count = 0; + tree method_array_type; + tree methods_decl; + tree super; + tree this_class_addr; + tree constant_pool_constructor; + tree interfaces = null_pointer_node; + int interface_len = 0; + tree type_decl = TYPE_NAME (type); + + this_class_addr = build_class_ref (type); + decl = TREE_OPERAND (this_class_addr, 0); + + /* Build Field array. */ + field = TYPE_FIELDS (type); + if (DECL_NAME (field) == NULL_TREE) + field = TREE_CHAIN (field); /* Skip dummy field for inherited data. */ + for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) + { + if (! DECL_ARTIFICIAL (field)) + { + tree init = make_field_value (field); + if (FIELD_STATIC (field)) + { + static_field_count++; + static_fields = tree_cons (NULL_TREE, init, static_fields); + rest_of_decl_compilation (field, (char*) 0, 1, 1); + } + else + { + instance_field_count++; + instance_fields = tree_cons (NULL_TREE, init, instance_fields); + } + } + } + field_count = static_field_count + instance_field_count; + if (field_count > 0) + { + static_fields = nreverse (static_fields); + instance_fields = nreverse (instance_fields); + static_fields = chainon (static_fields, instance_fields); + field_array_type = build_prim_array_type (field_type_node, field_count); + fields_decl = build_decl (VAR_DECL, mangled_classname ("_FL_", type), + field_array_type); + DECL_INITIAL (fields_decl) = build (CONSTRUCTOR, field_array_type, + NULL_TREE, static_fields); + TREE_STATIC (fields_decl) = 1; + DECL_ARTIFICIAL (fields_decl) = 1; + DECL_IGNORED_P (fields_decl) = 1; + rest_of_decl_compilation (fields_decl, (char*) 0, 1, 0); + } + else + fields_decl = NULL_TREE; + + /* Build Method array. */ + for (method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (type)); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree init = make_method_value (method, this_class_addr); + method_count++; + methods = tree_cons (NULL_TREE, init, methods); + } + method_array_type = build_prim_array_type (method_type_node, method_count); + methods_decl = build_decl (VAR_DECL, mangled_classname ("_MT_", type), + method_array_type); + DECL_INITIAL (methods_decl) = build (CONSTRUCTOR, method_array_type, + NULL_TREE, nreverse (methods)); + TREE_STATIC (methods_decl) = 1; + DECL_ARTIFICIAL (methods_decl) = 1; + DECL_IGNORED_P (methods_decl) = 1; + rest_of_decl_compilation (methods_decl, (char*) 0, 1, 0); + + if (flag_assume_compiled + && ! CLASS_ABSTRACT (type_decl) && ! CLASS_INTERFACE (type_decl)) + { + tree dtable = get_dispatch_table (type, this_class_addr); + dtable_decl = build_dtable_decl (type); + DECL_INITIAL (dtable_decl) = dtable; + TREE_STATIC (dtable_decl) = 1; + DECL_ARTIFICIAL (dtable_decl) = 1; + DECL_IGNORED_P (dtable_decl) = 1; + TREE_PUBLIC (dtable_decl) = 1; + rest_of_decl_compilation (dtable_decl, (char*) 0, 1, 0); + } + + super = CLASSTYPE_SUPER (type); + if (super == NULL_TREE) + super = null_pointer_node; + else if (flag_assume_compiled) + super = build_class_ref (super); + else + { + int super_index = alloc_class_constant (super); + super = build_int_2 (super_index, 0); + TREE_TYPE (super) == ptr_type_node; + } + + /* Build and emit the array of implemented interfaces. */ + if (type != object_type_node) + interface_len = TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (type)) - 1; + if (interface_len > 0) + { + tree init = NULL_TREE; + int i; + tree interface_array_type, idecl; + interface_array_type + = build_prim_array_type (class_ptr_type, interface_len); + idecl = build_decl (VAR_DECL, mangled_classname ("_IF_", type), + interface_array_type); + for (i = interface_len; i > 0; i--) + { + tree child = TREE_VEC_ELT (TYPE_BINFO_BASETYPES (type), i); + tree iclass = BINFO_TYPE (child); + tree index; + if (flag_assume_compiled) + index = build_class_ref (iclass); + else + { + int int_index = alloc_class_constant (iclass); + index = build_int_2 (int_index, 0); + TREE_TYPE (index) == ptr_type_node; + } + init = tree_cons (NULL_TREE, index, init); + } + DECL_INITIAL (idecl) = build (CONSTRUCTOR, interface_array_type, + NULL_TREE, init); + TREE_STATIC (idecl) = 1; + DECL_ARTIFICIAL (idecl) = 1; + DECL_IGNORED_P (idecl) = 1; + interfaces = build1 (ADDR_EXPR, ptr_type_node, idecl); + rest_of_decl_compilation (idecl, (char*) 0, 1, 0); + } + + constant_pool_constructor = build_constants_constructor (); + + START_RECORD_CONSTRUCTOR (temp, object_type_node); +#if 0 + PUSH_FIELD_VALUE (temp, "dtable", NULL_TREE); +#else + PUSH_FIELD_VALUE (temp, "dtable", + build1 (ADDR_EXPR, dtable_ptr_type, class_dtable_decl)); +#endif + PUSH_FIELD_VALUE (temp, "sync_info", null_pointer_node); + FINISH_RECORD_CONSTRUCTOR (temp); + START_RECORD_CONSTRUCTOR (cons, class_type_node); + PUSH_SUPER_VALUE (cons, temp); + PUSH_FIELD_VALUE (cons, "next", null_pointer_node); + PUSH_FIELD_VALUE (cons, "name", + build_utf8_ref (build_internal_class_name (type))); + PUSH_FIELD_VALUE (cons, "accflags", + build_int_2 (get_access_flags_from_decl (type_decl), 0)); + + PUSH_FIELD_VALUE (cons, "superclass", super); + PUSH_FIELD_VALUE (cons, "subclass_head", null_pointer_node); + PUSH_FIELD_VALUE (cons, "subclass_next", null_pointer_node); + PUSH_FIELD_VALUE (cons, "constants", constant_pool_constructor); + PUSH_FIELD_VALUE (cons, "methods", + build1 (ADDR_EXPR, method_ptr_type_node, methods_decl)); + PUSH_FIELD_VALUE (cons, "nmethods", build_int_2 (method_count, 0)); + PUSH_FIELD_VALUE (cons, "msize", TYPE_NVIRTUALS (type)); + PUSH_FIELD_VALUE (cons, "fields", + fields_decl == NULL_TREE ? null_pointer_node + : build1 (ADDR_EXPR, field_ptr_type_node, fields_decl)); + PUSH_FIELD_VALUE (cons, "bfsize", size_in_bytes (type)); + PUSH_FIELD_VALUE (cons, "nfields", build_int_2 (field_count, 0)); + PUSH_FIELD_VALUE (cons, "nsfields", build_int_2 (static_field_count, 0)); + /* For now, we let Kaffe fill in the dtable. */ + PUSH_FIELD_VALUE (cons, "dtable", + dtable_decl == NULL_TREE ? null_pointer_node + : build1 (ADDR_EXPR, dtable_ptr_type, dtable_decl)); + PUSH_FIELD_VALUE (cons, "interfaces", interfaces); + PUSH_FIELD_VALUE (cons, "loader", null_pointer_node); + PUSH_FIELD_VALUE (cons, "interface_len", build_int_2 (interface_len, 0)); + PUSH_FIELD_VALUE (cons, "state", + flag_assume_compiled ? integer_four_node + : integer_two_node); + + method = lookup_java_method (type, + finalize_identifier_node, void_signature_node); + PUSH_FIELD_VALUE (cons, "final", + method == NULL ? integer_zero_node : integer_one_node); + + FINISH_RECORD_CONSTRUCTOR (cons); + + DECL_INITIAL (decl) = cons; + rest_of_decl_compilation (decl, (char*) 0, 1, 0); +} + +/* Return 2 if CLASS is compiled by this compilation job; + return 1 if CLASS can otherwise be assumed to be compiled; + return 0 if we cannot assume that CLASS is compiled. + Returns 1 for primitive and 0 for array types. */ +int +is_compiled_class (class) + tree class; +{ + if (TREE_CODE (class) == POINTER_TYPE) + class = TREE_TYPE (class); + if (TREE_CODE (class) != RECORD_TYPE) /* Primitive types are static. */ + return 1; + if (TYPE_ARRAY_P (class)) + return 0; + if (class == current_class) + return 2; + if ((TYPE_LANG_SPECIFIC (class) && TYPE_LANG_SPECIFIC (class)->jcf && + TYPE_LANG_SPECIFIC (class)->jcf->seen_in_zip)) + { + /* The class was seen in the current ZIP file and will be + available as a compiled class in the future but may not have + been loaded already. Load it if necessary. This prevent + build_class_ref () from crashing. This should take into + consideration class specified in a multiple class file + command line. FIXME if necessary. */ + + if (!CLASS_LOADED_P (class)) + load_class (class, 1); + return 2; + } + + if (flag_assume_compiled) + { + if (!CLASS_LOADED_P (class)) + load_class (class, 1); + return 1; + } + + return 0; +} + +/* Append the mangled name of TYPE onto OBSTACK. */ + +void +append_gpp_mangled_type (obstack, type) + struct obstack *obstack; + tree type; +{ + char buf[8]; + int len; + char *ptr; + switch (TREE_CODE (type)) + { + char code; + case BOOLEAN_TYPE: code = 'b'; goto primitive; + case CHAR_TYPE: code = 'w'; goto primitive; + case VOID_TYPE: code = 'v'; goto primitive; + case INTEGER_TYPE: + /* Get the original type instead of the arguments promoted type. + Avoid symbol name clashes. Should call a function to do that. + FIXME. */ + if (type == promoted_short_type_node) + type = short_type_node; + if (type == promoted_byte_type_node) + type = byte_type_node; + switch (TYPE_PRECISION (type)) + { + case 8: code = 'c'; goto primitive; + case 16: code = 's'; goto primitive; + case 32: code = 'i'; goto primitive; + case 64: code = 'x'; goto primitive; + default: goto bad_type; + } + primitive: + obstack_1grow (obstack, code); + break; + case REAL_TYPE: + switch (TYPE_PRECISION (type)) + { + case 32: code = 'f'; goto primitive; + case 64: code = 'd'; goto primitive; + default: goto bad_type; + } + case POINTER_TYPE: + type = TREE_TYPE (type); + obstack_1grow (obstack, 'P'); + case RECORD_TYPE: + if (TYPE_ARRAY_P (type)) + { + obstack_grow (obstack, "t6JArray1Z", sizeof("t6JArray1Z")-1); + append_gpp_mangled_type (obstack, TYPE_ARRAY_ELEMENT (type)); + } + else + { + char *class_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))); + append_gpp_mangled_classtype (obstack, class_name); + } + break; + bad_type: + default: + fatal ("internal error - trying to mangle unknown type"); + } +} + +/* Build the mangled name of the `class' field. */ + +static tree +mangle_class_field (class) + tree class; +{ + tree name; + obstack_grow (&temporary_obstack, "_CL_", 4); + append_gpp_mangled_type (&temporary_obstack, class); + obstack_1grow (&temporary_obstack, '\0'); + name = get_identifier (obstack_base (&temporary_obstack)); + obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); + return name; +} + +/* Build the mangled (assembly-level) name of the static field FIELD. */ + +tree +mangle_static_field (field) + tree field; +{ + tree class = DECL_CONTEXT (field); + tree name = DECL_NAME (field); + int encoded_len; +#if ! defined (NO_DOLLAR_IN_LABEL) || ! defined (NO_DOT_IN_LABEL) + obstack_1grow (&temporary_obstack, '_'); +#else + obstack_grow (&temporary_obstack, "__static_", 9); +#endif + append_gpp_mangled_type (&temporary_obstack, class); + encoded_len = unicode_mangling_length (IDENTIFIER_POINTER (name), + IDENTIFIER_LENGTH (name)); + if (encoded_len > 0) + { + obstack_1grow (&temporary_obstack, 'U'); + } +#ifndef NO_DOLLAR_IN_LABEL + obstack_1grow (&temporary_obstack, '$'); +#else /* NO_DOLLAR_IN_LABEL */ +#ifndef NO_DOT_IN_LABEL + obstack_1grow (&temporary_obstack, '.'); +#else /* NO_DOT_IN_LABEL */ + obstack_1grow (&temporary_obstack, '_'); +#endif /* NO_DOT_IN_LABEL */ +#endif /* NO_DOLLAR_IN_LABEL */ + if (encoded_len > 0) + { + emit_unicode_mangled_name (&temporary_obstack, + IDENTIFIER_POINTER (name), + IDENTIFIER_LENGTH (name)); + } + else + { + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (name), + IDENTIFIER_LENGTH (name)); + } + obstack_1grow (&temporary_obstack, '\0'); + name = get_identifier (obstack_base (&temporary_obstack)); + obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); + return name; +} + +/* Build a VAR_DECL for the dispatch table (vtable) for class TYPE. */ + +tree +build_dtable_decl (type) + tree type; +{ + tree name; + obstack_grow (&temporary_obstack, "__vt_", 5); + append_gpp_mangled_type (&temporary_obstack, type); + obstack_1grow (&temporary_obstack, '\0'); + name = get_identifier (obstack_base (&temporary_obstack)); + obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); + return build_decl (VAR_DECL, name, dtable_type); +} + +/* Pre-pend the TYPE_FIELDS of THIS_CLASS with a dummy FIELD_DECL for the + fields inherited from SUPER_CLASS. */ + +void +push_super_field (this_class, super_class) + tree this_class, super_class; +{ + tree base_decl; + push_obstacks (&permanent_obstack, &permanent_obstack); + base_decl = build_decl (FIELD_DECL, NULL_TREE, super_class); + pop_obstacks (); + DECL_IGNORED_P (base_decl) = 1; + TREE_CHAIN (base_decl) = TYPE_FIELDS (this_class); + TYPE_FIELDS (this_class) = base_decl; + DECL_SIZE (base_decl) = TYPE_SIZE (super_class); +} + +void +layout_class (this_class) + tree this_class; +{ + tree super_class = CLASSTYPE_SUPER (this_class); + tree handle_type = CLASS_TO_HANDLE_TYPE (this_class); + tree method_decl, field; + tree dtable_count; + int i; + + if (super_class) + { + /* Class seen in source are now complete and can be layed out. + Once layed out, a class seen in the source has its + CLASS_LOADED_P flag set */ + if (CLASS_FROM_SOURCE_P (super_class) && !CLASS_LOADED_P (super_class)) + safe_layout_class (super_class); + if (! CLASS_LOADED_P (super_class)) + load_class (super_class, 1); + if (TREE_CODE (TYPE_SIZE (super_class)) == ERROR_MARK) + { + TYPE_SIZE (this_class) = error_mark_node; + return; + } + dtable_count = TYPE_NVIRTUALS (super_class); + + if (TYPE_SIZE (this_class) == NULL_TREE) + push_super_field (this_class, super_class); + } + else + { + dtable_count = integer_zero_node; + } + + for (field = TYPE_FIELDS (this_class); + field != NULL_TREE; field = TREE_CHAIN (field)) + { + if (FIELD_STATIC (field)) + { + /* Set DECL_ASSEMBLER_NAME to something suitably mangled. */ + DECL_ASSEMBLER_NAME (field) = mangle_static_field (field); + } + } + + layout_type (this_class); + + TYPE_METHODS (handle_type) = nreverse (TYPE_METHODS (handle_type)); + + for (method_decl = TYPE_METHODS (handle_type), i = 0; + method_decl; method_decl = TREE_CHAIN (method_decl), i++) + { + char *ptr; + char buf[8]; + char *asm_name; + tree method_name = DECL_NAME (method_decl); +#if 1 + /* Remove this once we no longer need old (Kaffe / JDK 1.0) mangling. */ + if (! flag_assume_compiled && METHOD_NATIVE (method_decl)) + { + for (ptr = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); + *ptr; ) + { + int ch = *ptr++; + if (ch == '.') + ch = '_'; + obstack_1grow (&temporary_obstack, (char) ch); + } + obstack_1grow (&temporary_obstack, (char) '_'); + if (method_name == init_identifier_node) + obstack_grow (&temporary_obstack, "INIT", 4); + else + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); + } + else +#endif + { + int len; tree arg, arglist, t; + int method_name_needs_escapes = 0; + if (method_name != init_identifier_node) + { + int encoded_len + = unicode_mangling_length (IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); + if (encoded_len > 0) + { + method_name_needs_escapes = 1; + emit_unicode_mangled_name (&temporary_obstack, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); + } + else + { + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_LENGTH (method_name)); + } + } + + obstack_grow (&temporary_obstack, "__", 2); + append_gpp_mangled_type (&temporary_obstack, this_class); + TREE_PUBLIC (method_decl) = 1; + + t = TREE_TYPE (method_decl); + arglist = TYPE_ARG_TYPES (t); + if (TREE_CODE (t) == METHOD_TYPE) + arglist = TREE_CHAIN (arglist); + for (arg = arglist; arg != NULL_TREE; ) + { + tree a = arglist; + tree argtype = TREE_VALUE (arg); + int tindex = 1; + if (TREE_CODE (argtype) == POINTER_TYPE) + { + /* This is O(N**2). Do we care? Cfr gcc/cp/method.c. */ + while (a != arg && argtype != TREE_VALUE (a)) + a = TREE_CHAIN (a), tindex++; + } + else + a = arg; + if (a != arg) + { + char buf[12]; + int nrepeats = 0; + do + { + arg = TREE_CHAIN (arg); nrepeats++; + } + while (arg != NULL_TREE && argtype == TREE_VALUE (arg)); + if (nrepeats > 1) + { + obstack_1grow (&temporary_obstack, 'N'); + sprintf (buf, "%d", nrepeats); + obstack_grow (&temporary_obstack, buf, strlen (buf)); + if (nrepeats > 9) + obstack_1grow (&temporary_obstack, '_'); + } + else + obstack_1grow (&temporary_obstack, 'T'); + sprintf (buf, "%d", tindex); + obstack_grow (&temporary_obstack, buf, strlen (buf)); + if (tindex > 9) + obstack_1grow (&temporary_obstack, '_'); + } + else + { + append_gpp_mangled_type (&temporary_obstack, argtype); + arg = TREE_CHAIN (arg); + } + } + if (method_name_needs_escapes) + obstack_1grow (&temporary_obstack, 'U'); + } + obstack_1grow (&temporary_obstack, '\0'); + asm_name = obstack_finish (&temporary_obstack); + DECL_ASSEMBLER_NAME (method_decl) = get_identifier (asm_name); + if (! METHOD_ABSTRACT (method_decl)) + make_function_rtl (method_decl); + obstack_free (&temporary_obstack, asm_name); + + if (method_name == init_identifier_node) + { + char *p = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class))); + for (ptr = p; *ptr; ) + { + if (*ptr++ == '.') + p = ptr; + } + DECL_NAME (method_decl) = get_identifier (p); + DECL_CONSTRUCTOR_P (method_decl) = 1; + } + else if (! METHOD_STATIC (method_decl)) + { + tree method_sig = build_java_argument_signature (TREE_TYPE (method_decl)); + tree super_method = lookup_argument_method (super_class, method_name, + method_sig); + if (super_method != NULL_TREE) + { + DECL_VINDEX (method_decl) = DECL_VINDEX (super_method); + if (DECL_VINDEX (method_decl) == NULL_TREE) + error_with_decl (method_decl, + "non-static method '%s' overrides static method"); +#if 0 + else if (TREE_TYPE (TREE_TYPE (method_decl)) + != TREE_TYPE (TREE_TYPE (super_method))) + { + error_with_decl (method_decl, + "Method `%s' redefined with different return type"); + error_with_decl (super_method, + "Overridden decl is here"); + } +#endif + } + else if (! METHOD_FINAL (method_decl) + && ! CLASS_FINAL (TYPE_NAME (this_class))) + { + DECL_VINDEX (method_decl) = dtable_count; + dtable_count = build_int_2 (1+TREE_INT_CST_LOW (dtable_count), 0); + } + } + } + TYPE_NVIRTUALS (this_class) = dtable_count; + +#ifdef JAVA_USE_HANDLES + layout_type (handle_type); +#endif +} + +static tree registered_class = NULL_TREE; + +void +register_class () +{ + static tree end; + tree node = TREE_OPERAND (build_class_ref (current_class), 0); + tree current = copy_node (node); + + XEXP (DECL_RTL (current), 0) = copy_rtx (XEXP (DECL_RTL(node), 0)); + if (!registered_class) + registered_class = current; + else + TREE_CHAIN (end) = current; + + end = current; +} + +/* Generate a function that gets called at start-up (static contructor) time, + which calls registerClass for all the compiled classes. */ + +void +emit_register_class () +{ + tree decl = getdecls (); + + extern tree get_file_function_name PROTO((int)); + tree init_name = get_file_function_name ('I'); + tree init_type = build_function_type (void_type_node, NULL_TREE); + tree init_decl; + tree t; + + start_sequence (); + init_decl = build_decl (FUNCTION_DECL, init_name, init_type); + DECL_ASSEMBLER_NAME (init_decl) = init_name; + TREE_STATIC (init_decl) = 1; + current_function_decl = init_decl; + DECL_RESULT (init_decl) = build_decl(RESULT_DECL, NULL_TREE, void_type_node); + /* DECL_EXTERNAL (init_decl) = 1;*/ + TREE_PUBLIC (init_decl) = 1; + pushlevel (0); + make_function_rtl (init_decl); + init_function_start (init_decl, input_filename, 0); + expand_function_start (init_decl, 0); + + for ( t = registered_class; t; t = TREE_CHAIN (t)) + emit_library_call (registerClass_libfunc, 0, VOIDmode, 1, + XEXP (DECL_RTL (t), 0), Pmode); + + expand_function_end (input_filename, 0, 0); + poplevel (1, 0, 1); + { + /* Force generation, even with -O3 or deeper. Gross hack. FIXME */ + extern int flag_inline_functions; + int saved_flag = flag_inline_functions; + flag_inline_functions = 0; + rest_of_compilation (init_decl); + flag_inline_functions = saved_flag; + } + current_function_decl = NULL_TREE; + assemble_constructor (IDENTIFIER_POINTER (init_name)); +} + +void +init_class_processing () +{ + registerClass_libfunc = gen_rtx (SYMBOL_REF, Pmode, "registerClass"); +} diff --git a/gcc/java/config-lang.in b/gcc/java/config-lang.in new file mode 100644 index 00000000000..571e65a734b --- /dev/null +++ b/gcc/java/config-lang.in @@ -0,0 +1,40 @@ +# Top level configure fragment for the GNU compiler for the Java(TM) +# language. +# Copyright (C) 1994, 1995 Free Software Foundation, Inc. + +#This file is part of GNU CC. + +#GNU CC 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, +#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 +#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. + +# Configure looks for the existence of this file to auto-config each language. +# We define several parameters used by configure: +# +# language - name of language as it would appear in $(LANGUAGES) +# compilers - value to add to $(COMPILERS) +# stagestuff - files to add to $(STAGESTUFF) +# diff_excludes - files to ignore when building diffs between two versions. + +language="java" + +compilers="jc1\$(exeext) jvgenmain\$(exeext)" + +stagestuff="jc1\$(exeext) gcj\$(exeext) jvgenmain\$(exeext) gcjh\$(exeext)" + +outputs=java/Makefile diff --git a/gcc/java/constants.c b/gcc/java/constants.c new file mode 100644 index 00000000000..696f6841130 --- /dev/null +++ b/gcc/java/constants.c @@ -0,0 +1,453 @@ +/* Handle the constant pool of the Java(TM) Virtual Machine. + Copyright (C) 1997 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +#include "config.h" +#include "tree.h" +#include "java-tree.h" +#include "jcf.h" +#include "system.h" + +extern struct obstack permanent_obstack; + +/* Set the INDEX'th constant in CPOOL to have the given TAG and VALUE. */ + +void +set_constant_entry (cpool, index, tag, value) + CPool *cpool; + int index; + int tag; + jword value; +{ + if (cpool->data == NULL) + { + cpool->capacity = 100; + cpool->tags = (uint8*) xmalloc (sizeof(uint8) * cpool->capacity); + cpool->data = (jword*) xmalloc (sizeof(jword) * cpool->capacity); + cpool->count = 1; + } + if (index >= cpool->capacity) + { + cpool->capacity *= 2; + if (index >= cpool->capacity) + cpool->capacity = index + 10; + cpool->tags = (uint8*) xrealloc (cpool->tags, + sizeof(uint8) * cpool->capacity); + cpool->data = (jword*) xrealloc (cpool->data, + sizeof(jword) * cpool->capacity); + } + if (index >= cpool->count) + cpool->count = index + 1; + cpool->tags[index] = tag; + cpool->data[index] = value; +} + +/* Find (or create) a constant pool entry matching TAG and VALUE. */ + +int +find_constant1 (cpool, tag, value) + CPool *cpool; + int tag; + jword value; +{ + int i; + for (i = cpool->count; --i > 0; ) + { + if (cpool->tags[i] == tag && cpool->data[i] == value) + return i; + } + i = cpool->count == 0 ? 1 : cpool->count; + set_constant_entry (cpool, i, tag, value); + return i; +} + +/* Find a double-word constant pool entry matching TAG and WORD1/WORD2. */ + +int +find_constant2 (cpool, tag, word1, word2) + CPool *cpool; + int tag; + jword word1, word2; +{ + int i; + for (i = cpool->count - 1; --i > 0; ) + { + if (cpool->tags[i] == tag + && cpool->data[i] == word1 + && cpool->data[i+1] == word2) + return i; + } + i = cpool->count == 0 ? 1 : cpool->count; + set_constant_entry (cpool, i, tag, word1); + set_constant_entry (cpool, i+1, 0, word2); + return i; +} + +int +find_utf8_constant (cpool, name) + CPool *cpool; + tree name; +{ + if (name == NULL_TREE) + return 0; + return find_constant1 (cpool, CONSTANT_Utf8, (jword) name); +} + +int +find_class_or_string_constant (cpool, tag, name) + CPool *cpool; + int tag; + tree name; +{ + int j = find_utf8_constant (cpool, name); + int i; + for (i = cpool->count; --i > 0; ) + { + if (cpool->tags[i] == tag && cpool->data[i] == j) + return i; + } + i = cpool->count; + set_constant_entry (cpool, i, tag, (jword) j); + return i; +} + +int +find_class_constant (cpool, type) + CPool *cpool; + tree type; +{ + return find_class_or_string_constant (cpool, CONSTANT_Class, + build_internal_class_name (type)); +} + +/* Find (or create) a CONSTANT_NameAndType matching NAME and TYPE. + Return its index in the constant pool CPOOL. */ + +int +find_name_and_type_constant (cpool, name, type) + CPool *cpool; + tree name; + tree type; +{ + int name_index = find_utf8_constant (cpool, name); + int type_index = find_utf8_constant (cpool, build_java_signature (type)); + return find_constant1 (cpool, CONSTANT_NameAndType, + (name_index << 16) | type_index); +} + +/* Find (or create) a CONSTANT_Fieldref for DECL (a FIELD_DECL or VAR_DECL). + Return its index in the constant pool CPOOL. */ + +int +find_fieldref_index (cpool, decl) + CPool *cpool; + tree decl; +{ + int class_index = find_class_constant (cpool, DECL_CONTEXT (decl)); + int name_type_index + = find_name_and_type_constant (cpool, DECL_NAME (decl), TREE_TYPE (decl)); + return find_constant1 (cpool, CONSTANT_Fieldref, + (class_index << 16) | name_type_index); +} + +/* Find (or create) a CONSTANT_Methodref for DECL (a FUNCTION_DECL). + Return its index in the constant pool CPOOL. */ + +int +find_methodref_index (cpool, decl) + CPool *cpool; + tree decl; +{ + int class_index = find_class_constant (cpool, DECL_CONTEXT (decl)); + tree name = DECL_CONSTRUCTOR_P (decl) ? init_identifier_node + : DECL_NAME (decl); + int name_type_index + = find_name_and_type_constant (cpool, name, TREE_TYPE (decl)); + /* Methodref or INterfacemethodRef - FIXME */ + return find_constant1 (cpool, CONSTANT_Methodref, + (class_index << 16) | name_type_index); +} + +#define PUT1(X) (*ptr++ = (X)) +#define PUT2(X) (PUT1((X) >> 8), PUT1(X)) +#define PUT4(X) (PUT2((X) >> 16), PUT2(X)) +#define PUTN(P, N) (bcopy(P, ptr, N), ptr += (N)) + +/* Give the number of bytes needed in a .class file for the CPOOL + constant pool. Includes the 2-byte constant_pool_count. */ + +int +count_constant_pool_bytes (cpool) + CPool *cpool; +{ + int size = 2; + int i = 1; + jword *datap = &cpool->data[1];; + for ( ; i < cpool->count; i++, datap++) + { + size++; + switch (cpool->tags[i]) + { + case CONSTANT_NameAndType: + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_Float: + case CONSTANT_Integer: + size += 4; + break; + case CONSTANT_Class: + case CONSTANT_String: + size += 2; + break; + case CONSTANT_Long: + case CONSTANT_Double: + size += 4; + break; + case CONSTANT_Utf8: + { + tree t = (tree) *datap; + int len = IDENTIFIER_LENGTH (t); + size += len + 2; + } + break; + } + } + return size; +} + +/* Write the constant pool CPOOL into BUFFER. + The length of BUFFER is LENGTH, which must match the needed length. */ + +void +write_constant_pool (cpool, buffer, length) + CPool *cpool; + unsigned char* buffer; + int length; +{ + unsigned char* ptr = buffer; + int i = 1; + jword *datap = &cpool->data[1]; + PUT2 (cpool->count); + for ( ; i < cpool->count; i++, datap++) + { + int tag = cpool->tags[i]; + PUT1 (tag); + switch (tag) + { + case CONSTANT_NameAndType: + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_Float: + case CONSTANT_Integer: + PUT4 (*datap); + break; + case CONSTANT_Class: + case CONSTANT_String: + PUT2 (*datap); + break; + break; + case CONSTANT_Long: + case CONSTANT_Double: + PUT4(*datap); + i++; + datap++; + PUT4 (*datap); + break; + case CONSTANT_Utf8: + { + tree t = (tree) *datap; + int len = IDENTIFIER_LENGTH (t); + PUT2 (len); + PUTN (IDENTIFIER_POINTER (t), len); + } + break; + } + } + if (ptr != buffer + length) + fatal("internal error - incorrect constant pool"); +} + +CPool *outgoing_cpool; + +/* If non-NULL, an ADDR_EXPR referencing a VAR_DECL containing + the constant data array for the current class. */ +tree current_constant_pool_data_ref; + +/* A Cache for build_int_2 (CONSTANT_XXX, 0). */ +static tree tag_nodes[13]; + +tree +get_tag_node (tag) + int tag; +{ + if (tag_nodes[tag] == NULL_TREE) + { + push_obstacks (&permanent_obstack, &permanent_obstack); + tag_nodes[tag] = build_int_2 (tag, 0); + pop_obstacks (); + } + return tag_nodes[tag]; +} + +/* Look for a constant pool entry that matches TAG and NAME. + Creates a new entry if not found. + TAG is one of CONSTANT_Utf8, CONSTANT_String or CONSTANT_Class. + NAME is an IDENTIFIER_NODE naming the Utf8 constant, string, or class. + Returns the index of the entry. */ + +int +alloc_name_constant (tag, name) + int tag; + tree name; +{ + return find_constant1 (outgoing_cpool, tag, (jword) name); +} + +/* Build an identifier for the internal name of reference type TYPE. */ + +tree +build_internal_class_name (type) + tree type; +{ + tree name; + if (TYPE_ARRAY_P (type)) + name = build_java_signature (type); + else + { + name = TYPE_NAME (type); + if (TREE_CODE (name) != IDENTIFIER_NODE) + name = DECL_NAME (name); + name = identifier_subst (name, "", '.', '/', ""); + } + return name; +} + +/* Look for a CONSTANT_Class entry for CLAS, creating a new one if needed. */ + +int +alloc_class_constant (clas) + tree clas; +{ + + return alloc_name_constant (CONSTANT_Class, + build_internal_class_name (clas)); +} + +/* Return a reference to the data array of the current constant pool. */ + +tree +build_constant_data_ref () +{ + if (current_constant_pool_data_ref == NULL_TREE) + { + tree decl; + tree decl_name = mangled_classname ("_CD_", current_class); + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = build_decl (VAR_DECL, decl_name, + build_array_type (ptr_type_node, + one_elt_array_domain_type)); + TREE_STATIC (decl) = 1; + make_decl_rtl (decl, NULL, 1); + pop_obstacks (); + current_constant_pool_data_ref + = build1 (ADDR_EXPR, ptr_type_node, decl); + } + return current_constant_pool_data_ref; +} + +/* Get the pointer value at the INDEX'th element of the constant pool. */ + +tree +build_ref_from_constant_pool (index) + int index; +{ + tree t = build_constant_data_ref (); + index *= int_size_in_bytes (ptr_type_node); + t = fold (build (PLUS_EXPR, ptr_type_node, + t, build_int_2 (index, 0))); + return build1 (INDIRECT_REF, ptr_type_node, t); +} + +/* Build an initializer for the constants field of the current constal pool. + Should only be called at top-level, since it may emit declarations. */ + +tree +build_constants_constructor () +{ + tree tags_value, data_value; + tree cons; + tree tags_list = NULL_TREE; + tree data_list = NULL_TREE; + int i; + for (i = outgoing_cpool->count; --i > 0; ) + { + tags_list + = tree_cons (NULL_TREE, get_tag_node (outgoing_cpool->tags[i]), + tags_list); + data_list + = tree_cons (NULL_TREE, build_utf8_ref ((tree)outgoing_cpool->data[i]), + data_list); + } + if (outgoing_cpool->count > 0) + { + tree index_type; + tree data_decl, tags_decl, tags_type; + tree max_index = build_int_2 (outgoing_cpool->count - 1, 0); + TREE_TYPE (max_index) = sizetype; + index_type = build_index_type (max_index); + + /* Add dummy 0'th element of constant pool. */ + tags_list = tree_cons (NULL_TREE, get_tag_node (0), tags_list); + data_list = tree_cons (NULL_TREE, null_pointer_node, data_list); + + data_decl = TREE_OPERAND (build_constant_data_ref (), 0); + TREE_TYPE (data_decl) = build_array_type (ptr_type_node, index_type), + DECL_INITIAL (data_decl) = build (CONSTRUCTOR, TREE_TYPE (data_decl), + NULL_TREE, data_list); + DECL_SIZE (data_decl) = TYPE_SIZE (TREE_TYPE (data_decl)); + rest_of_decl_compilation (data_decl, (char*) 0, 1, 0); + data_value = build_address_of (data_decl); + + tags_type = build_array_type (unsigned_byte_type_node, index_type); + tags_decl = build_decl (VAR_DECL, mangled_classname ("_CT_", + current_class), + tags_type); + TREE_STATIC (tags_decl) = 1; + DECL_INITIAL (tags_decl) = build (CONSTRUCTOR, tags_type, + NULL_TREE, tags_list); + rest_of_decl_compilation (tags_decl, (char*) 0, 1, 0); + tags_value = build_address_of (tags_decl); + } + else + { + data_value = null_pointer_node; + tags_value = null_pointer_node; + } + START_RECORD_CONSTRUCTOR (cons, constants_type_node); + PUSH_FIELD_VALUE (cons, "size", build_int_2 (outgoing_cpool->count, 0)); + PUSH_FIELD_VALUE (cons, "tags", tags_value); + PUSH_FIELD_VALUE (cons, "data", data_value); + FINISH_RECORD_CONSTRUCTOR (cons); + return cons; +} diff --git a/gcc/java/convert.h b/gcc/java/convert.h new file mode 100644 index 00000000000..1e1373e5e41 --- /dev/null +++ b/gcc/java/convert.h @@ -0,0 +1,24 @@ +/* Definition of conversion functions. + Copyright (C) 1993 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Written by Jeffrey Hsu */ + +extern tree convert_to_boolean PROTO ((tree, tree)); +extern tree convert_to_char PROTO ((tree, tree)); diff --git a/gcc/java/decl.c b/gcc/java/decl.c new file mode 100644 index 00000000000..a12931fe1ba --- /dev/null +++ b/gcc/java/decl.c @@ -0,0 +1,1561 @@ +/* Process declarations and variables for the GNU compiler for the + Java(TM) language. + + Copyright (C) 1996, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Hacked by Per Bothner February 1996. */ + +#include "config.h" +#include "tree.h" +#include "java-tree.h" +#include "jcf.h" +#include "system.h" + +/* The DECL_MAP is a mapping from (index, type) to a decl node. + If index < max_locals, it is the index of a local variable. + if index >= max_locals, then index-max_locals is a stack slot. + The DECL_MAP mapping is represented as a TREE_VEC whose elements + are a list of decls (VAR_DECL or PARM_DECL) chained by + DECL_LOCAL_SLOT_CHAIN; the index finds the TREE_VEC element, and then + we search the chain for a decl with a matching TREE_TYPE. */ + +tree decl_map; + +/* A list of local variables VAR_DECLs for this method that we have seen + debug information, but we have not reached their starting (byte) PC yet. */ + +tree pending_local_decls = NULL_TREE; + +/* Push a local variable or stack slot into the decl_map, + and assign it an rtl. */ + +tree +push_jvm_slot (index, decl) + int index; + tree decl; +{ + struct rtx_def *rtl = NULL; + tree type = TREE_TYPE (decl); + tree tmp; + + DECL_CONTEXT (decl) = current_function_decl; + layout_decl (decl, 0); + + /* See if we have an appropriate rtl (i.e. same mode) at this index. + If so, we must use it. */ + tmp = TREE_VEC_ELT (decl_map, index); + while (tmp != NULL_TREE) + { + if (TYPE_MODE (type) == TYPE_MODE (TREE_TYPE (tmp))) + rtl = DECL_RTL (tmp); + if (rtl != NULL) + break; + tmp = DECL_LOCAL_SLOT_CHAIN (tmp); + } + if (rtl != NULL) + DECL_RTL (decl) = rtl; + else + { + if (index >= DECL_MAX_LOCALS (current_function_decl)) + DECL_REGISTER (decl) = 1; + expand_decl (decl); + } + + /* Now link the decl into the decl_map. */ + if (DECL_LANG_SPECIFIC (decl) == NULL) + { + DECL_LANG_SPECIFIC (decl) + = (struct lang_decl *) permalloc (sizeof (struct lang_decl_var)); + DECL_LOCAL_START_PC (decl) = 0; + DECL_LOCAL_END_PC (decl) = DECL_CODE_LENGTH (current_function_decl); + DECL_LOCAL_SLOT_NUMBER (decl) = index; + } + DECL_LOCAL_SLOT_CHAIN (decl) = TREE_VEC_ELT (decl_map, index); + TREE_VEC_ELT (decl_map, index) = decl; + return decl; +} + +/* Find a VAR_DECL (or PARM_DECL) at local index INDEX that has type TYPE, + that is valid at PC (or -1 if any pc). + If there is no existing matching decl, allocate one. + If we find a decl with matching modes but different types, + we re-use the rtl, but create a new decl. */ + +tree +find_local_variable (index, type, pc) + int index; + tree type; + int pc; +{ + struct rtx_def *rtl = NULL; + tree decl = TREE_VEC_ELT (decl_map, index); + tree best = NULL_TREE; + while (decl != NULL_TREE) + { + int in_range; + in_range = pc < 0 + || (pc >= DECL_LOCAL_START_PC (decl) + && pc < DECL_LOCAL_END_PC (decl)); + + if ((TREE_TYPE (decl) == type + || (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE + && type == ptr_type_node)) + && in_range) + { + if (best == NULL_TREE + || (TREE_TYPE (decl) == type && TREE_TYPE (best) != type) + || DECL_LOCAL_START_PC (decl) > DECL_LOCAL_START_PC (best) + || DECL_LOCAL_END_PC (decl) < DECL_LOCAL_START_PC (decl)) + best = decl; + } + decl = DECL_LOCAL_SLOT_CHAIN (decl); + } + if (best != NULL_TREE) + return best; + return push_jvm_slot (index, build_decl (VAR_DECL, NULL_TREE, type)); +} + + +/* Same as find_local_index, except that INDEX is a stack index. */ + +tree +find_stack_slot (index, type) + int index; + tree type; +{ + return find_local_variable (index + DECL_MAX_LOCALS (current_function_decl), + type, -1); +} + +struct binding_level + { + /* A chain of _DECL nodes for all variables, constants, functions, + * and typedef types. These are in the reverse of the order supplied. + */ + tree names; + + /* For each level, a list of shadowed outer-level local definitions + to be restored when this level is popped. + Each link is a TREE_LIST whose TREE_PURPOSE is an identifier and + whose TREE_VALUE is its old definition (a kind of ..._DECL node). */ + tree shadowed; + + /* For each level (except not the global one), + a chain of BLOCK nodes for all the levels + that were entered and exited one level down. */ + tree blocks; + + /* The BLOCK node for this level, if one has been preallocated. + If 0, the BLOCK is allocated (if needed) when the level is popped. */ + tree this_block; + + /* The binding level which this one is contained in (inherits from). */ + struct binding_level *level_chain; + + /* 1 means make a BLOCK for this level regardless of all else. + 2 for temporary binding contours created by the compiler. */ + char keep; + + /* Nonzero means make a BLOCK if this level has any subblocks. */ + char keep_if_subblocks; + + /* Nonzero if this level can safely have additional + cleanup-needing variables added to it. */ + char more_cleanups_ok; + char have_cleanups; + + /* The bytecode PC that marks the end of this level. */ + int end_pc; + }; + +#define NULL_BINDING_LEVEL (struct binding_level *) NULL + +/* The binding level currently in effect. */ + +static struct binding_level *current_binding_level; + +/* A chain of binding_level structures awaiting reuse. */ + +static struct binding_level *free_binding_level; + +/* The outermost binding level, for names of file scope. + This is created when the compiler is started and exists + through the entire run. */ + +static struct binding_level *global_binding_level; + +/* Binding level structures are initialized by copying this one. */ + +static struct binding_level clear_binding_level + = {NULL_TREE, NULL_TREE, NULL_TREE, NULL_TREE, + NULL_BINDING_LEVEL, 0, 0, 0, 0, 1000000000}; + +#if 0 +/* A list (chain of TREE_LIST nodes) of all LABEL_DECLs in the function + that have names. Here so we can clear out their names' definitions + at the end of the function. */ + +static tree named_labels; + +/* A list of LABEL_DECLs from outer contexts that are currently shadowed. */ + +static tree shadowed_labels; +#endif + +int flag_traditional; + +/* Nonzero means unconditionally make a BLOCK for the next level pushed. */ + +static int keep_next_level_flag; + +/* Nonzero means make a BLOCK for the next level pushed + if it has subblocks. */ + +static int keep_next_if_subblocks; + +/* The FUNCTION_DECL for the function currently being compiled, + or 0 if between functions. */ +tree current_function_decl; + +/* The type node for the ordinary character type. */ +tree char_type_node; + +tree object_type_node; +tree object_ptr_type_node; +tree string_type_node; +tree throwable_type_node; + +tree boolean_type_node; + +tree float_type_node; +tree double_type_node; + +/* a VOID_TYPE node. */ + +tree void_type_node; +tree ptr_type_node; +tree return_address_type_node; + +tree integer_type_node; + +tree byte_type_node; +tree short_type_node; +tree int_type_node; +tree long_type_node; + +tree promoted_byte_type_node; +tree promoted_short_type_node; +tree promoted_char_type_node; +tree promoted_boolean_type_node; + +tree unsigned_byte_type_node; +tree unsigned_short_type_node; +tree unsigned_int_type_node; +tree unsigned_long_type_node; + +/* The type for struct methodtable. */ +tree methodtable_type; +tree methodtable_ptr_type; + +tree utf8const_type; +tree utf8const_ptr_type; +tree class_type_node; +tree class_ptr_type; +tree field_type_node; +tree field_ptr_type_node; +tree field_info_union_node; +tree jexception_type; +tree jexception_ptr_type; +tree lineNumberEntry_type; +tree lineNumbers_type; +tree constants_type_node; +tree dtable_type; +tree dtable_ptr_type; +tree method_type_node; +tree method_ptr_type_node; +tree nativecode_ptr_array_type_node; +tree one_elt_array_domain_type; +tree access_flags_type_node; +tree class_dtable_decl; + +/* a node which has tree code ERROR_MARK, and whose type is itself. + All erroneous expressions are replaced with this node. All functions + that accept nodes as arguments should avoid generating error messages + if this node is one of the arguments, since it is undesirable to get + multiple error messages from one error in the input. */ + +tree error_mark_node; + +/* Two expressions that are constants with value zero. + The first is of type `int', the second of type `void *'. */ +tree integer_zero_node; +tree null_pointer_node; + +/* Nodes for boolean constants TRUE and FALSE. */ +tree boolean_true_node, boolean_false_node; + +tree TYPE_identifier_node; +tree init_identifier_node; +tree clinit_identifier_node; +tree finalize_identifier_node; +tree void_signature_node; +tree length_identifier_node; +tree this_identifier_node; +tree super_identifier_node; + +/* References to internal libjava functions we use. */ +tree alloc_object_node; +tree soft_instanceof_node; +tree soft_checkcast_node; +tree soft_initclass_node; +tree soft_newarray_node; +tree soft_anewarray_node; +tree soft_multianewarray_node; +tree soft_badarrayindex_node; +tree throw_node; +tree soft_checkarraystore_node; +tree soft_monitorenter_node; +tree soft_monitorexit_node; +tree soft_lookupinterfacemethod_node; +tree soft_fmod_node; + +/* Build (and pushdecl) a "promoted type" for all standard + types shorter than int. */ + +static tree +push_promoted_type (name, actual_type) + char *name; + tree actual_type; +{ + tree type = make_node (TREE_CODE (actual_type)); +#if 1 + tree in_min = TYPE_MIN_VALUE (int_type_node); + tree in_max = TYPE_MAX_VALUE (int_type_node); +#else + tree in_min = TYPE_MIN_VALUE (actual_type); + tree in_max = TYPE_MAX_VALUE (actual_type); +#endif + TYPE_MIN_VALUE (type) = build_int_2 (TREE_INT_CST_LOW (in_min), + TREE_INT_CST_HIGH (in_min)); + TREE_TYPE (TYPE_MIN_VALUE (type)) = type; + TYPE_MAX_VALUE (type) = build_int_2 (TREE_INT_CST_LOW (in_max), + TREE_INT_CST_HIGH (in_max)); + TREE_TYPE (TYPE_MAX_VALUE (type)) = type; + TYPE_PRECISION (type) = TYPE_PRECISION (int_type_node); + layout_type (type); + pushdecl (build_decl (TYPE_DECL, get_identifier (name), type)); + return type; +} + +/* Nodes for integer constants. */ +tree integer_one_node, integer_two_node, integer_four_node; +tree integer_negative_one_node; + +/* Return a definition for a builtin function named NAME and whose data type + is TYPE. TYPE should be a function type with argument types. + FUNCTION_CODE tells later passes how to compile calls to this function. + See tree.h for its possible values. + + If LIBRARY_NAME is nonzero, use that for DECL_ASSEMBLER_NAME, + the name to be called if we can't opencode the function. */ + +tree +builtin_function (name, type, function_code, library_name) + char *name; + tree type; + enum built_in_function function_code; + char *library_name; +{ + tree decl = build_decl (FUNCTION_DECL, get_identifier (name), type); + DECL_EXTERNAL (decl) = 1; + TREE_PUBLIC (decl) = 1; + if (library_name) + DECL_ASSEMBLER_NAME (decl) = get_identifier (library_name); + make_decl_rtl (decl, NULL_PTR, 1); + pushdecl (decl); + if (function_code != NOT_BUILT_IN) + { + DECL_BUILT_IN (decl) = 1; + DECL_FUNCTION_CODE (decl) = function_code; + } + return decl; +} + +void +init_decl_processing () +{ + tree field; + tree t; + + current_function_decl = NULL; + current_binding_level = NULL_BINDING_LEVEL; + free_binding_level = NULL_BINDING_LEVEL; + pushlevel (0); /* make the binding_level structure for global names */ + global_binding_level = current_binding_level; + + error_mark_node = make_node (ERROR_MARK); + TREE_TYPE (error_mark_node) = error_mark_node; + + /* Create sizetype first - needed for other types. */ + sizetype = make_unsigned_type (POINTER_SIZE); + size_zero_node = build_int_2 (0, 0); + TREE_TYPE (size_zero_node) = sizetype; + size_one_node = build_int_2 (1, 0); + TREE_TYPE (size_one_node) = sizetype; + + byte_type_node = make_signed_type (8); + pushdecl (build_decl (TYPE_DECL, get_identifier ("byte"), byte_type_node)); + short_type_node = make_signed_type (16); + pushdecl (build_decl (TYPE_DECL, get_identifier ("short"), short_type_node)); + int_type_node = make_signed_type (32); + pushdecl (build_decl (TYPE_DECL, get_identifier ("int"), int_type_node)); + long_type_node = make_signed_type (64); + pushdecl (build_decl (TYPE_DECL, get_identifier ("long"), long_type_node)); + + unsigned_byte_type_node = make_unsigned_type (8); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned byte"), + unsigned_byte_type_node)); + unsigned_short_type_node = make_unsigned_type (16); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned short"), + unsigned_short_type_node)); + unsigned_int_type_node = make_unsigned_type (32); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned int"), + unsigned_int_type_node)); + unsigned_long_type_node = make_unsigned_type (64); + pushdecl (build_decl (TYPE_DECL, get_identifier ("unsigned long"), + unsigned_long_type_node)); + + integer_type_node = int_type_node; + + integer_zero_node = build_int_2 (0, 0); + integer_one_node = build_int_2 (1, 0); + integer_two_node = build_int_2 (2, 0); + integer_four_node = build_int_2 (4, 0); + integer_negative_one_node = build_int_2 (-1, 0); + + void_type_node = make_node (VOID_TYPE); + pushdecl (build_decl (TYPE_DECL, get_identifier ("void"), void_type_node)); + layout_type (void_type_node); /* Uses size_zero_node */ + ptr_type_node = build_pointer_type (void_type_node); + t = make_node (VOID_TYPE); + layout_type (t); /* Uses size_zero_node */ + return_address_type_node = build_pointer_type (t); + + null_pointer_node = build_int_2 (0, 0); + TREE_TYPE (null_pointer_node) = ptr_type_node; + +#if 0 + /* Make a type to be the domain of a few array types + whose domains don't really matter. + 200 is small enough that it always fits in size_t + and large enough that it can hold most function names for the + initializations of __FUNCTION__ and __PRETTY_FUNCTION__. */ + short_array_type_node = build_prim_array_type (short_type_node, 200); +#endif + char_type_node = make_node (CHAR_TYPE); + TYPE_PRECISION (char_type_node) = 16; + fixup_unsigned_type (char_type_node); + pushdecl (build_decl (TYPE_DECL, get_identifier ("char"), char_type_node)); + + boolean_type_node = make_node (BOOLEAN_TYPE); + TYPE_PRECISION (boolean_type_node) = 1; + fixup_unsigned_type (boolean_type_node); + pushdecl (build_decl (TYPE_DECL, get_identifier ("boolean"), + boolean_type_node)); + boolean_false_node = TYPE_MIN_VALUE (boolean_type_node); + boolean_true_node = TYPE_MAX_VALUE (boolean_type_node); + + promoted_byte_type_node + = push_promoted_type ("promoted_byte", byte_type_node); + promoted_short_type_node + = push_promoted_type ("promoted_short", short_type_node); + promoted_char_type_node + = push_promoted_type ("promoted_char", char_type_node); + promoted_boolean_type_node + = push_promoted_type ("promoted_boolean", boolean_type_node); + + float_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (float_type_node) = 32; + pushdecl (build_decl (TYPE_DECL, get_identifier ("float"), + float_type_node)); + layout_type (float_type_node); + + double_type_node = make_node (REAL_TYPE); + TYPE_PRECISION (double_type_node) = 64; + pushdecl (build_decl (TYPE_DECL, get_identifier ("double"), + double_type_node)); + layout_type (double_type_node); + + object_type_node = lookup_class (get_identifier ("java.lang.Object")); + object_ptr_type_node = promote_type (object_type_node); + string_type_node = lookup_class (get_identifier ("java.lang.String")); + class_type_node = lookup_class (get_identifier ("java.lang.Class")); + throwable_type_node = lookup_class (get_identifier ("java.lang.Throwable")); + + methodtable_type = make_node (RECORD_TYPE); + layout_type (methodtable_type); + pushdecl (build_decl (TYPE_DECL, get_identifier ("methodtable"), + methodtable_type)); + methodtable_ptr_type = build_pointer_type (methodtable_type); + + TYPE_identifier_node = get_identifier ("TYPE"); + init_identifier_node = get_identifier (""); + clinit_identifier_node = get_identifier (""); + finalize_identifier_node = get_identifier ("finalize"); + void_signature_node = get_identifier ("()V"); + length_identifier_node = get_identifier ("length"); + this_identifier_node = get_identifier ("this"); + super_identifier_node = get_identifier ("super"); + + /* for lack of a better place to put this stub call */ + init_expr_processing(); + + utf8const_type = make_node (RECORD_TYPE); + PUSH_FIELD (utf8const_type, field, "hash", unsigned_short_type_node); + PUSH_FIELD (utf8const_type, field, "length", unsigned_short_type_node); + FINISH_RECORD (utf8const_type); + utf8const_ptr_type = build_pointer_type (utf8const_type); + + constants_type_node = make_node (RECORD_TYPE); + PUSH_FIELD (constants_type_node, field, "size", unsigned_int_type_node); + PUSH_FIELD (constants_type_node, field, "tags", ptr_type_node); + PUSH_FIELD (constants_type_node, field, "data", ptr_type_node); + FINISH_RECORD (constants_type_node); + pushdecl (build_decl (TYPE_DECL, get_identifier ("constants"), + constants_type_node)); + + access_flags_type_node = unsigned_short_type_node; + + dtable_type = make_node (RECORD_TYPE); + dtable_ptr_type = build_pointer_type (dtable_type); + + PUSH_FIELD (object_type_node, field, "dtable", dtable_ptr_type); + PUSH_FIELD (object_type_node, field, "sync_info", ptr_type_node); + for (t = TYPE_FIELDS (object_type_node); t != NULL_TREE; t = TREE_CHAIN (t)) + FIELD_PRIVATE (t) = 1; + FINISH_RECORD (object_type_node); + + class_dtable_decl = build_dtable_decl (class_type_node); + TREE_STATIC (class_dtable_decl) = 1; + DECL_ARTIFICIAL (class_dtable_decl) = 1; + DECL_IGNORED_P (class_dtable_decl) = 1; + rest_of_decl_compilation (class_dtable_decl, (char*) 0, 1, 0); + + field_type_node = make_node (RECORD_TYPE); + field_ptr_type_node = build_pointer_type (field_type_node); + method_type_node = make_node (RECORD_TYPE); + method_ptr_type_node = build_pointer_type (method_type_node); + + set_super_info (0, class_type_node, object_type_node, 0); + set_super_info (0, string_type_node, object_type_node, 0); + class_ptr_type = build_pointer_type (class_type_node); + + PUSH_FIELD (class_type_node, field, "next", class_ptr_type); + PUSH_FIELD (class_type_node, field, "name", utf8const_ptr_type); + PUSH_FIELD (class_type_node, field, "accflags", access_flags_type_node); + PUSH_FIELD (class_type_node, field, "superclass", class_ptr_type); + PUSH_FIELD (class_type_node, field, "subclass_head", class_ptr_type); + PUSH_FIELD (class_type_node, field, "subclass_next", class_ptr_type); + PUSH_FIELD (class_type_node, field, "constants", constants_type_node); + PUSH_FIELD (class_type_node, field, "methods", method_ptr_type_node); + PUSH_FIELD (class_type_node, field, "nmethods", short_type_node); + PUSH_FIELD (class_type_node, field, "msize", short_type_node); + PUSH_FIELD (class_type_node, field, "fields", field_ptr_type_node); + PUSH_FIELD (class_type_node, field, "bfsize", int_type_node); + PUSH_FIELD (class_type_node, field, "nfields", short_type_node); + PUSH_FIELD (class_type_node, field, "nsfields", short_type_node); + PUSH_FIELD (class_type_node, field, "dtable", dtable_ptr_type); + PUSH_FIELD (class_type_node, field, "interfaces", + build_pointer_type (class_ptr_type)); + PUSH_FIELD (class_type_node, field, "loader", ptr_type_node); + PUSH_FIELD (class_type_node, field, "interface_len", short_type_node); + PUSH_FIELD (class_type_node, field, "state", byte_type_node); + PUSH_FIELD (class_type_node, field, "final", byte_type_node); + for (t = TYPE_FIELDS (class_type_node); t != NULL_TREE; t = TREE_CHAIN (t)) + FIELD_PRIVATE (t) = 1; + push_super_field (class_type_node, object_type_node); + FINISH_RECORD (class_type_node); + pushdecl (build_decl (TYPE_DECL, get_identifier ("Class"), class_type_node)); + + field_info_union_node = make_node (UNION_TYPE); + PUSH_FIELD (field_info_union_node, field, "boffset", int_type_node); + PUSH_FIELD (field_info_union_node, field, "addr", ptr_type_node); +#if 0 + PUSH_FIELD (field_info_union_node, field, "idx", unsigned_short_type_node); +#endif + layout_type (field_info_union_node); + + PUSH_FIELD (field_type_node, field, "name", utf8const_ptr_type); + PUSH_FIELD (field_type_node, field, "type", class_ptr_type); + PUSH_FIELD (field_type_node, field, "accflags", access_flags_type_node); + PUSH_FIELD (field_type_node, field, "bsize", unsigned_short_type_node); + PUSH_FIELD (field_type_node, field, "info", field_info_union_node); + FINISH_RECORD (field_type_node); + CLASS_LOADED_P (field_type_node) = 1; + pushdecl (build_decl (TYPE_DECL, get_identifier ("Field"), field_type_node)); + + one_elt_array_domain_type = build_index_type (integer_one_node); + nativecode_ptr_array_type_node + = build_array_type (nativecode_ptr_type_node, one_elt_array_domain_type); + + PUSH_FIELD (dtable_type, field, "class", class_ptr_type); + PUSH_FIELD (dtable_type, field, "methods", nativecode_ptr_array_type_node); + FINISH_RECORD (dtable_type); + pushdecl (build_decl (TYPE_DECL, get_identifier ("dispatchTable"), dtable_type)); + +#define jint_type int_type_node +#define jint_ptr_type ptr_type_node + + jexception_type = make_node (RECORD_TYPE); + PUSH_FIELD (jexception_type, field, "start_pc", ptr_type_node); + PUSH_FIELD (jexception_type, field, "end_pc", ptr_type_node); + PUSH_FIELD (jexception_type, field, "handler_pc", ptr_type_node); + PUSH_FIELD (jexception_type, field, "catch_type", class_ptr_type); + FINISH_RECORD (jexception_type); + pushdecl (build_decl (TYPE_DECL, get_identifier ("jexception"), field_type_node)); + jexception_ptr_type = build_pointer_type (jexception_type); + + lineNumberEntry_type = make_node (RECORD_TYPE); + PUSH_FIELD (lineNumberEntry_type, field, "line_nr", unsigned_short_type_node); + PUSH_FIELD (lineNumberEntry_type, field, "start_pc", ptr_type_node); + FINISH_RECORD (lineNumberEntry_type); + + lineNumbers_type = make_node (RECORD_TYPE); + PUSH_FIELD (lineNumbers_type, field, "length", unsigned_int_type_node); + FINISH_RECORD (lineNumbers_type); + +#define instn_ptr_type_node ptr_type_node /* XXX JH */ + +#define lineNumbers_ptr_type_node build_pointer_type(lineNumbers_type) + + PUSH_FIELD (method_type_node, field, "name", utf8const_ptr_type); + PUSH_FIELD (method_type_node, field, "signature", utf8const_ptr_type); + PUSH_FIELD (method_type_node, field, "accflags", access_flags_type_node); + PUSH_FIELD (method_type_node, field, "ncode", nativecode_ptr_type_node); + FINISH_RECORD (method_type_node); + CLASS_LOADED_P (method_type_node) = 1; + pushdecl (build_decl (TYPE_DECL, get_identifier ("Method"), method_type_node)); + + t = tree_cons (NULL_TREE, class_ptr_type, + build_tree_list (NULL_TREE, int_type_node)); + alloc_object_node = builtin_function ("_Jv_AllocObject", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR); + soft_initclass_node = builtin_function ("_Jv_InitClass", + build_function_type (void_type_node, + t), + NOT_BUILT_IN, NULL_PTR); + t = build_tree_list (NULL_TREE, void_type_node); + throw_node = builtin_function ("_Jv_Throw", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR); + soft_monitorenter_node + = builtin_function ("_Jv_MonitorEnter", + build_function_type (int_type_node, t), + NOT_BUILT_IN, NULL_PTR); + soft_monitorexit_node + = builtin_function ("_Jv_MonitorExit", + build_function_type (int_type_node, t), + NOT_BUILT_IN, NULL_PTR); + + t = tree_cons (NULL_TREE, int_type_node, + build_tree_list (NULL_TREE, int_type_node)); + soft_newarray_node + = builtin_function ("_Jv_NewArray", + build_function_type(ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR ); + + t = tree_cons (NULL_TREE, int_type_node, + tree_cons (NULL_TREE, class_ptr_type, + build_tree_list (NULL_TREE, object_ptr_type_node))); + soft_anewarray_node + = builtin_function ("_Jv_NewObjectArray", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR ); + + t = tree_cons (NULL_TREE, ptr_type_node, + build_tree_list (NULL_TREE, int_type_node)); + soft_multianewarray_node + = builtin_function ("_Jv_NewMultiArray", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR ); + + t = build_function_type (void_type_node, NULL_TREE); + soft_badarrayindex_node + = builtin_function ("_Jv_ThrowBadArrayIndex", t, NOT_BUILT_IN, NULL_PTR ); + TREE_THIS_VOLATILE (soft_badarrayindex_node) = 1; + TREE_SIDE_EFFECTS (soft_badarrayindex_node) = 1; + + t = tree_cons (NULL_TREE, class_ptr_type, + build_tree_list (NULL_TREE, object_ptr_type_node)); + soft_checkcast_node + = builtin_function ("_Jv_CheckCast", + build_function_type (ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR); + t = tree_cons (NULL_TREE, object_ptr_type_node, + build_tree_list (NULL_TREE, class_ptr_type)); + soft_instanceof_node + = builtin_function ("_Jv_IsInstanceOf", + build_function_type (promoted_boolean_type_node, t), + NOT_BUILT_IN, NULL_PTR); + t = tree_cons (NULL_TREE, object_ptr_type_node, + build_tree_list (NULL_TREE, object_ptr_type_node)); + soft_checkarraystore_node + = builtin_function ("_Jv_CheckArrayStore", + build_function_type (void_type_node, t), + NOT_BUILT_IN, NULL_PTR); + t = tree_cons (NULL_TREE, ptr_type_node, + tree_cons (NULL_TREE, ptr_type_node, + build_tree_list (NULL_TREE, ptr_type_node))); + soft_lookupinterfacemethod_node + = builtin_function ("_Jv_LookupInterfaceMethod", + build_function_type(ptr_type_node, t), + NOT_BUILT_IN, NULL_PTR); + t = tree_cons (NULL_TREE, double_type_node, + build_tree_list (NULL_TREE, double_type_node)); + soft_fmod_node + = builtin_function ("__builtin_fmod", + build_function_type (double_type_node, t), + BUILT_IN_FMOD, "fmod"); +#if 0 + t = tree_cons (NULL_TREE, float_type_node, + build_tree_list (NULL_TREE, float_type_node)); + soft_fmodf_node + = builtin_function ("__builtin_fmodf", + build_function_type (float_type_node, t), + BUILT_IN_FMOD, "fmodf"); +#endif + + init_class_processing (); +} + + +/* Look up NAME in the current binding level and its superiors + in the namespace of variables, functions and typedefs. + Return a ..._DECL node of some kind representing its definition, + or return 0 if it is undefined. */ + +tree +lookup_name (name) + tree name; +{ + register tree val; + if (current_binding_level != global_binding_level + && IDENTIFIER_LOCAL_VALUE (name)) + val = IDENTIFIER_LOCAL_VALUE (name); + else + val = IDENTIFIER_GLOBAL_VALUE (name); + return val; +} + +/* Similar to `lookup_name' but look only at current binding level and + the previous one if its the parameter level. */ + +tree +lookup_name_current_level (name) + tree name; +{ + register tree t; + + if (current_binding_level == global_binding_level) + return IDENTIFIER_GLOBAL_VALUE (name); + + if (IDENTIFIER_LOCAL_VALUE (name) == 0) + return 0; + + for (t = current_binding_level->names; t; t = TREE_CHAIN (t)) + if (DECL_NAME (t) == name) + break; + + return t; +} + +/* Use a binding level to record a labeled block declaration */ + +void +push_labeled_block (lb) + tree lb; +{ + register tree name = DECL_NAME (LABELED_BLOCK_LABEL (lb)); + register struct binding_level *b = current_binding_level; + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + if (oldlocal != 0) + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + TREE_CHAIN (lb) = b->names; + b->names = lb; + IDENTIFIER_LOCAL_VALUE (name) = lb; +} + +/* Pop the current binding level, reinstalling values for the previous + labeled block */ + +void +pop_labeled_block () +{ + struct binding_level *b = current_binding_level; + tree label = b->names; + IDENTIFIER_LOCAL_VALUE (DECL_NAME (LABELED_BLOCK_LABEL (label))) = + NULL_TREE; + if (b->shadowed) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (b->shadowed)) = + TREE_VALUE (b->shadowed); + + /* Pop the current level, and free the structure for reuse. */ + current_binding_level = current_binding_level->level_chain; + b->level_chain = free_binding_level; + free_binding_level = b; +} + +/* Record a decl-node X as belonging to the current lexical scope. + Check for errors (such as an incompatible declaration for the same + name already seen in the same scope). + + Returns either X or an old decl for the same name. + If an old decl is returned, it may have been smashed + to agree with what X says. */ + +tree +pushdecl (x) + tree x; +{ + register tree t; + register tree name = DECL_NAME (x); + register struct binding_level *b = current_binding_level; + + DECL_CONTEXT (x) = current_function_decl; + if (name) + { + char *file; + int line; + int different_binding_level = 0; + + t = lookup_name_current_level (name); + if (t != 0 && t == error_mark_node) + /* error_mark_node is 0 for a while during initialization! */ + { + t = 0; + error_with_decl (x, "`%s' used prior to declaration"); + } + + if (t != 0) + { + file = DECL_SOURCE_FILE (t); + line = DECL_SOURCE_LINE (t); + } + + /* If we're naming a hitherto-unnamed type, set its TYPE_NAME + to point to the TYPE_DECL. + Since Java does not have typedefs, a type can only have + one (true) name, given by a class, interface, or builtin. */ + if (TREE_CODE (x) == TYPE_DECL + && TYPE_NAME (TREE_TYPE (x)) == 0 + && TREE_TYPE (x) != error_mark_node) + { + TYPE_NAME (TREE_TYPE (x)) = x; + TYPE_STUB_DECL (TREE_TYPE (x)) = x; + } + + /* This name is new in its binding level. + Install the new declaration and return it. */ + if (b == global_binding_level) + { + /* Install a global value. */ + + IDENTIFIER_GLOBAL_VALUE (name) = x; + } + else + { + /* Here to install a non-global value. */ + tree oldlocal = IDENTIFIER_LOCAL_VALUE (name); + tree oldglobal = IDENTIFIER_GLOBAL_VALUE (name); + IDENTIFIER_LOCAL_VALUE (name) = x; + +#if 0 + /* Warn if shadowing an argument at the top level of the body. */ + if (oldlocal != 0 && !DECL_EXTERNAL (x) + /* This warning doesn't apply to the parms of a nested fcn. */ + && ! current_binding_level->parm_flag + /* Check that this is one level down from the parms. */ + && current_binding_level->level_chain->parm_flag + /* Check that the decl being shadowed + comes from the parm level, one level up. */ + && chain_member (oldlocal, current_binding_level->level_chain->names)) + { + if (TREE_CODE (oldlocal) == PARM_DECL) + pedwarn ("declaration of `%s' shadows a parameter", + IDENTIFIER_POINTER (name)); + else + pedwarn ("declaration of `%s' shadows a symbol from the parameter list", + IDENTIFIER_POINTER (name)); + } + + /* Maybe warn if shadowing something else. */ + else if (warn_shadow && !DECL_EXTERNAL (x) + /* No shadow warnings for internally generated vars. */ + && DECL_SOURCE_LINE (x) != 0 + /* No shadow warnings for vars made for inlining. */ + && ! DECL_FROM_INLINE (x)) + { + char *warnstring = 0; + + if (TREE_CODE (x) == PARM_DECL + && current_binding_level->level_chain->parm_flag) + /* Don't warn about the parm names in function declarator + within a function declarator. + It would be nice to avoid warning in any function + declarator in a declaration, as opposed to a definition, + but there is no way to tell it's not a definition. */ + ; + else if (oldlocal != 0 && TREE_CODE (oldlocal) == PARM_DECL) + warnstring = "declaration of `%s' shadows a parameter"; + else if (oldlocal != 0) + warnstring = "declaration of `%s' shadows previous local"; + else if (IDENTIFIER_GLOBAL_VALUE (name) != 0 + && IDENTIFIER_GLOBAL_VALUE (name) != error_mark_node) + warnstring = "declaration of `%s' shadows global declaration"; + + if (warnstring) + warning (warnstring, IDENTIFIER_POINTER (name)); + } +#endif + + /* If storing a local value, there may already be one (inherited). + If so, record it for restoration when this binding level ends. */ + if (oldlocal != 0) + b->shadowed = tree_cons (name, oldlocal, b->shadowed); + } + } + + /* Put decls on list in reverse order. + We will reverse them later if necessary. */ + TREE_CHAIN (x) = b->names; + b->names = x; + + return x; +} +void +pushdecl_force_head (x) + tree x; +{ + current_binding_level->names = x; +} + +/* Like pushdecl, only it places X in GLOBAL_BINDING_LEVEL, if appropriate. */ + +tree +pushdecl_top_level (x) + tree x; +{ + register tree t; + register struct binding_level *b = current_binding_level; + + current_binding_level = global_binding_level; + t = pushdecl (x); + current_binding_level = b; + return t; +} + +/* Nonzero if we are currently in the global binding level. */ + +int +global_bindings_p () +{ + return current_binding_level == global_binding_level; +} + +/* Return the list of declarations of the current level. + Note that this list is in reverse order unless/until + you nreverse it; and when you do nreverse it, you must + store the result back using `storedecls' or you will lose. */ + +tree +getdecls () +{ + return current_binding_level->names; +} + +/* Create a new `struct binding_level'. */ + +static +struct binding_level * +make_binding_level () +{ + /* NOSTRICT */ + return (struct binding_level *) xmalloc (sizeof (struct binding_level)); +} + +void +pushlevel (unused) + int unused; +{ + register struct binding_level *newlevel = NULL_BINDING_LEVEL; + +#if 0 + /* If this is the top level of a function, + just make sure that NAMED_LABELS is 0. */ + + if (current_binding_level == global_binding_level) + named_labels = 0; +#endif + + /* Reuse or create a struct for this binding level. */ + + if (free_binding_level) + { + newlevel = free_binding_level; + free_binding_level = free_binding_level->level_chain; + } + else + { + newlevel = make_binding_level (); + } + + /* Add this level to the front of the chain (stack) of levels that + are active. */ + + *newlevel = clear_binding_level; + newlevel->level_chain = current_binding_level; + current_binding_level = newlevel; + newlevel->keep = keep_next_level_flag; + keep_next_level_flag = 0; + newlevel->keep_if_subblocks = keep_next_if_subblocks; + keep_next_if_subblocks = 0; +} + +/* Exit a binding level. + Pop the level off, and restore the state of the identifier-decl mappings + that were in effect when this level was entered. + + If KEEP is nonzero, this level had explicit declarations, so + and create a "block" (a BLOCK node) for the level + to record its declarations and subblocks for symbol table output. + + If FUNCTIONBODY is nonzero, this level is the body of a function, + so create a block as if KEEP were set and also clear out all + label names. + + If REVERSE is nonzero, reverse the order of decls before putting + them into the BLOCK. */ + +tree +poplevel (keep, reverse, functionbody) + int keep; + int reverse; + int functionbody; +{ + register tree link; + /* The chain of decls was accumulated in reverse order. + Put it into forward order, just for cleanliness. */ + tree decls; + tree subblocks = current_binding_level->blocks; + tree block = 0; + tree decl; + int block_previously_created; + + keep |= current_binding_level->keep; + + /* Get the decls in the order they were written. + Usually current_binding_level->names is in reverse order. + But parameter decls were previously put in forward order. */ + + if (reverse) + current_binding_level->names + = decls = nreverse (current_binding_level->names); + else + decls = current_binding_level->names; + + /* Output any nested inline functions within this block + if they weren't already output. */ + + for (decl = decls; decl; decl = TREE_CHAIN (decl)) + if (TREE_CODE (decl) == FUNCTION_DECL + && ! TREE_ASM_WRITTEN (decl) + && DECL_INITIAL (decl) != 0 + && TREE_ADDRESSABLE (decl)) + { + /* If this decl was copied from a file-scope decl + on account of a block-scope extern decl, + propagate TREE_ADDRESSABLE to the file-scope decl. + + DECL_ABSTRACT_ORIGIN can be set to itself if warn_return_type is + true, since then the decl goes through save_for_inline_copying. */ + if (DECL_ABSTRACT_ORIGIN (decl) != 0 + && DECL_ABSTRACT_ORIGIN (decl) != decl) + TREE_ADDRESSABLE (DECL_ABSTRACT_ORIGIN (decl)) = 1; + else + { + push_function_context (); + output_inline_function (decl); + pop_function_context (); + } + } + + /* If there were any declarations in that level, + or if this level is a function body, + create a BLOCK to record them for the life of this function. */ + + block = 0; + block_previously_created = (current_binding_level->this_block != 0); + if (block_previously_created) + block = current_binding_level->this_block; + else if (keep || functionbody + || (current_binding_level->keep_if_subblocks && subblocks != 0)) + block = make_node (BLOCK); + if (block != 0) + { + BLOCK_VARS (block) = decls; + BLOCK_TYPE_TAGS (block) = NULL_TREE; + BLOCK_SUBBLOCKS (block) = subblocks; + remember_end_note (block); + } + + /* In each subblock, record that this is its superior. */ + + for (link = subblocks; link; link = TREE_CHAIN (link)) + BLOCK_SUPERCONTEXT (link) = block; + + /* Clear out the meanings of the local variables of this level. */ + + for (link = decls; link; link = TREE_CHAIN (link)) + { + tree name = DECL_NAME (link); + if (name != 0 && IDENTIFIER_LOCAL_VALUE (name) == link) + { + /* If the ident. was used or addressed via a local extern decl, + don't forget that fact. */ + if (DECL_EXTERNAL (link)) + { + if (TREE_USED (link)) + TREE_USED (name) = 1; + if (TREE_ADDRESSABLE (link)) + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (link)) = 1; + } + IDENTIFIER_LOCAL_VALUE (name) = 0; + } + } + + /* Restore all name-meanings of the outer levels + that were shadowed by this level. */ + + for (link = current_binding_level->shadowed; link; link = TREE_CHAIN (link)) + IDENTIFIER_LOCAL_VALUE (TREE_PURPOSE (link)) = TREE_VALUE (link); + + /* If the level being exited is the top level of a function, + check over all the labels, and clear out the current + (function local) meanings of their names. */ + + if (functionbody) + { + /* If this is the top level block of a function, + the vars are the function's parameters. + Don't leave them in the BLOCK because they are + found in the FUNCTION_DECL instead. */ + + BLOCK_VARS (block) = 0; + + /* Clear out the definitions of all label names, + since their scopes end here, + and add them to BLOCK_VARS. */ + +#if 0 + for (link = named_labels; link; link = TREE_CHAIN (link)) + { + register tree label = TREE_VALUE (link); + + if (DECL_INITIAL (label) == 0) + { + error_with_decl (label, "label `%s' used but not defined"); + /* Avoid crashing later. */ + define_label (input_filename, lineno, + DECL_NAME (label)); + } + else if (warn_unused && !TREE_USED (label)) + warning_with_decl (label, "label `%s' defined but not used"); + IDENTIFIER_LABEL_VALUE (DECL_NAME (label)) = 0; + + /* Put the labels into the "variables" of the + top-level block, so debugger can see them. */ + TREE_CHAIN (label) = BLOCK_VARS (block); + BLOCK_VARS (block) = label; + } +#endif + } + + /* Pop the current level, and free the structure for reuse. */ + + { + register struct binding_level *level = current_binding_level; + current_binding_level = current_binding_level->level_chain; + + level->level_chain = free_binding_level; + free_binding_level = level; + } + + /* Dispose of the block that we just made inside some higher level. */ + if (functionbody) + DECL_INITIAL (current_function_decl) = block; + else if (block) + { + if (!block_previously_created) + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); + } + /* If we did not make a block for the level just exited, + any blocks made for inner levels + (since they cannot be recorded as subblocks in that level) + must be carried forward so they will later become subblocks + of something else. */ + else if (subblocks) + current_binding_level->blocks + = chainon (current_binding_level->blocks, subblocks); + + /* Set the TYPE_CONTEXTs for all of the tagged types belonging to this + binding contour so that they point to the appropriate construct, i.e. + either to the current FUNCTION_DECL node, or else to the BLOCK node + we just constructed. + + Note that for tagged types whose scope is just the formal parameter + list for some function type specification, we can't properly set + their TYPE_CONTEXTs here, because we don't have a pointer to the + appropriate FUNCTION_TYPE node readily available to us. For those + cases, the TYPE_CONTEXTs of the relevant tagged type nodes get set + in `grokdeclarator' as soon as we have created the FUNCTION_TYPE + node which will represent the "scope" for these "parameter list local" + tagged types. + */ + + if (block) + TREE_USED (block) = 1; + return block; +} + +void +maybe_pushlevels (pc) + int pc; +{ + while (pending_local_decls != NULL_TREE && + DECL_LOCAL_START_PC (pending_local_decls) <= pc) + { + tree *ptr = &pending_local_decls; + tree decl = *ptr; + int end_pc = DECL_LOCAL_END_PC (decl); + + while (*ptr != NULL_TREE + && DECL_LOCAL_START_PC (*ptr) <= pc + && DECL_LOCAL_END_PC (*ptr) == end_pc) + ptr = &TREE_CHAIN (*ptr); + pending_local_decls = *ptr; + *ptr = NULL_TREE; + + /* Force non-nested range to be nested in current range. */ + if (end_pc > current_binding_level->end_pc) + end_pc = current_binding_level->end_pc; + + pushlevel (1); + expand_start_bindings (0); + current_binding_level->end_pc = end_pc; + + current_binding_level->names = decl; + for ( ; decl != NULL_TREE; decl = TREE_CHAIN (decl)) + { + push_jvm_slot (DECL_LOCAL_SLOT_NUMBER (decl), decl); + } + } +} + +void +maybe_poplevels (pc) + int pc; +{ + while (current_binding_level->end_pc <= pc) + { + expand_end_bindings (getdecls (), 1, 0); + poplevel (1, 0, 0); + } +} + +/* Insert BLOCK at the end of the list of subblocks of the + current binding level. This is used when a BIND_EXPR is expanded, + to handle the BLOCK node inside the BIND_EXPR. */ + +void +insert_block (block) + tree block; +{ + TREE_USED (block) = 1; + abort (); + current_binding_level->blocks + = chainon (current_binding_level->blocks, block); +} + +/* Set the BLOCK node for the innermost scope + (the one we are currently in). */ + +void +set_block (block) + register tree block; +{ + current_binding_level->this_block = block; +} + +/* integrate_decl_tree calls this function. */ + +void +copy_lang_decl (node) + tree node; +{ + int lang_decl_size + = TREE_CODE (node) == VAR_DECL ? sizeof (struct lang_decl_var) + : sizeof (struct lang_decl); + struct lang_decl *x = (struct lang_decl *) oballoc (lang_decl_size); + bcopy (DECL_LANG_SPECIFIC (node), x, lang_decl_size); + DECL_LANG_SPECIFIC (node) = x; +} + +/* If DECL has a cleanup, build and return that cleanup here. + This is a callback called by expand_expr. */ + +tree +maybe_build_cleanup (decl) + tree decl; +{ + /* There are no cleanups in Java (I think). */ + return NULL_TREE; +} + +void +give_name_to_locals (jcf) + JCF *jcf; +{ + int i, n = DECL_LOCALVARIABLES_OFFSET (current_function_decl); + tree parm; + pending_local_decls = NULL_TREE; + if (n == 0) + return; + JCF_SEEK (jcf, n); + n = JCF_readu2 (jcf); + for (i = 0; i < n; i++) + { + int start_pc = JCF_readu2 (jcf); + int length = JCF_readu2 (jcf); + int name_index = JCF_readu2 (jcf); + int signature_index = JCF_readu2 (jcf); + int slot = JCF_readu2 (jcf); + tree name = get_name_constant (jcf, name_index); + tree type = promote_type (parse_signature (jcf, signature_index)); + if (slot < DECL_ARG_SLOT_COUNT (current_function_decl) + && start_pc == 0 + && length == DECL_CODE_LENGTH (current_function_decl)) + { + tree decl = TREE_VEC_ELT (decl_map, slot); + DECL_NAME (decl) = name; + DECL_ASSEMBLER_NAME (decl) = name; + if (TREE_CODE (decl) != PARM_DECL || TREE_TYPE (decl) != type) + warning ("bad type in parameter debug info"); + } + else + { + tree *ptr; + int end_pc = start_pc + length; + tree decl = build_decl (VAR_DECL, name, type); + if (end_pc > DECL_CODE_LENGTH (current_function_decl)) + { + warning_with_decl (decl, + "bad PC range for debug info for local `%s'"); + end_pc = DECL_CODE_LENGTH (current_function_decl); + } + DECL_LANG_SPECIFIC (decl) + = (struct lang_decl *) permalloc (sizeof (struct lang_decl_var)); + DECL_LOCAL_SLOT_NUMBER (decl) = slot; + DECL_LOCAL_START_PC (decl) = start_pc; + DECL_LOCAL_END_PC (decl) = end_pc; + + /* Now insert the new decl in the proper place in + pending_local_decls. We are essentially doing an insertion sort, + which works fine, since the list input will normally already + be sorted. */ + ptr = &pending_local_decls; + while (*ptr != NULL_TREE + && (DECL_LOCAL_START_PC (*ptr) > start_pc + || (DECL_LOCAL_START_PC (*ptr) == start_pc + && DECL_LOCAL_END_PC (*ptr) < end_pc))) + ptr = &TREE_CHAIN (*ptr); + TREE_CHAIN (decl) = *ptr; + *ptr = decl; + } + } + + pending_local_decls = nreverse (pending_local_decls); + + /* Fill in default names for the parameters. */ + for (parm = DECL_ARGUMENTS (current_function_decl), i = 0; + parm != NULL_TREE; parm = TREE_CHAIN (parm), i++) + { + if (DECL_NAME (parm) == NULL_TREE) + { + int arg_i = METHOD_STATIC (current_function_decl) ? i+1 : i; + if (arg_i == 0) + DECL_NAME (parm) = get_identifier ("this"); + else + { + char buffer[12]; + sprintf (buffer, "ARG_%d", arg_i); + DECL_NAME (parm) = get_identifier (buffer); + } + DECL_ASSEMBLER_NAME (parm) = DECL_NAME (parm); + } + } +} + +void +complete_start_java_method (fndecl) + tree fndecl; +{ + + DECL_RESULT (fndecl) = build_decl (RESULT_DECL, NULL_TREE, + TREE_TYPE (TREE_TYPE (fndecl))); + + if (! flag_emit_class_files) + { + /* Initialize the RTL code for the function. */ + init_function_start (fndecl, input_filename, lineno); + + /* Set up parameters and prepare for return, for the function. */ + expand_function_start (fndecl, 0); + } + + /* Allocate further tree nodes temporarily during compilation + of this function only. */ + temporary_allocation (); + +#if 0 + /* If this fcn was already referenced via a block-scope `extern' decl (or + an implicit decl), propagate certain information about the usage. */ + if (TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (current_function_decl))) + TREE_ADDRESSABLE (current_function_decl) = 1; + +#endif + + if (METHOD_SYNCHRONIZED (fndecl)) + { + /* FIXME: surround the function body by a try/finally set. */ + } + + /* Push local variables. Function compiled from source code are + using a different local variables management, and for them, + pushlevel shouldn't be called from here. */ + if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (fndecl))) + + { + pushlevel (2); + if (! flag_emit_class_files) + expand_start_bindings (1); + } +} + +void +start_java_method (fndecl) + tree fndecl; +{ + tree tem, *ptr; + int i; + + current_function_decl = fndecl; + announce_function (fndecl); + + i = DECL_MAX_LOCALS(fndecl) + DECL_MAX_STACK(fndecl); + decl_map = make_tree_vec (i); + type_map = (tree *) oballoc (i * sizeof (tree)); + + pushlevel (1); /* Push parameters. */ + + ptr = &DECL_ARGUMENTS (fndecl); + for (tem = TYPE_ARG_TYPES (TREE_TYPE (fndecl)), i = 0; + tem != NULL_TREE; tem = TREE_CHAIN (tem), i++) + { + tree parm_name = NULL_TREE, parm_decl; + if (i >= DECL_MAX_LOCALS(fndecl)) + fatal ("function has more parameters than local slots"); + + parm_decl = build_decl (PARM_DECL, parm_name, TREE_VALUE (tem)); + DECL_CONTEXT (parm_decl) = fndecl; + DECL_ARG_TYPE (parm_decl) = TREE_TYPE (parm_decl); + + *ptr = parm_decl; + ptr = &TREE_CHAIN (parm_decl); + + /* Add parm_decl to the decl_map. */ + push_jvm_slot (i, parm_decl); + + type_map[i] = TREE_TYPE (parm_decl); + if (TYPE_IS_WIDE (TREE_TYPE (parm_decl))) + { + i++; + type_map[i] = void_type_node; + } + } + *ptr = NULL_TREE; + DECL_ARG_SLOT_COUNT (current_function_decl) = i; + + while (i < DECL_MAX_LOCALS(fndecl)) + type_map[i++] = NULL_TREE; + + complete_start_java_method (fndecl); +} + +void +end_java_method () +{ + tree fndecl = current_function_decl; + + expand_end_bindings (getdecls (), 1, 0); + /* pop out of function */ + poplevel (1, 1, 0); + + /* pop out of its parameters */ + poplevel (1, 0, 1); + + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + emit_handlers (); + + /* Generate rtl for function exit. */ + expand_function_end (input_filename, lineno, 0); + + /* Run the optimizers and output assembler code for this function. */ + rest_of_compilation (fndecl); + + current_function_decl = NULL_TREE; + permanent_allocation (1); +} + +tree +build_decl_no_layout (code, name, type) + enum tree_code code; + tree name, type; +{ + tree decl = build_decl (TYPE_DECL, name, type); + TREE_SET_CODE (decl, code); + return decl; +} diff --git a/gcc/java/except.c b/gcc/java/except.c new file mode 100644 index 00000000000..46c0f7cd713 --- /dev/null +++ b/gcc/java/except.c @@ -0,0 +1,278 @@ +/* Handle exceptions for GNU compiler for the Java(TM) language. + Copyright (C) 1997 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +#include +#include "config.h" +#include "tree.h" +#include "real.h" +#include "rtl.h" +#include "java-tree.h" +#include "javaop.h" +#include "java-opcodes.h" +#include "jcf.h" +#include "except.h" +#include "java-except.h" +#include "eh-common.h" + +extern struct obstack permanent_obstack; + +struct eh_range *current_method_handlers; + +struct eh_range *current_try_block = NULL; + +struct eh_range *eh_range_freelist = NULL; + +/* These variables are used to speed up find_handler. */ + +static int cache_range_start, cache_range_end; +static struct eh_range *cache_range; +static struct eh_range *cache_next_child; + +/* A dummy range that represents the entire method. */ + +struct eh_range whole_range; + +/* Search for the most specific eh_range containing PC. + Assume PC is within RANGE. + CHILD is a list of children of RANGE such that any + previous children have end_pc values that are too low. */ + +static struct eh_range * +find_handler_in_range (pc, range, child) + int pc; + struct eh_range *range; + register struct eh_range *child; +{ + for (; child != NULL; child = child->next_sibling) + { + if (pc < child->start_pc) + break; + if (pc <= child->end_pc) + return find_handler_in_range (pc, child, child->first_child); + } + cache_range = range; + cache_range_start = pc; + cache_next_child = child; + cache_range_end = child == NULL ? range->end_pc : child->start_pc; + return range; +} + +/* Find the inner-most handler that contains PC. */ + +struct eh_range * +find_handler (pc) + int pc; +{ + struct eh_range *h; + if (pc >= cache_range_start) + { + h = cache_range; + if (pc < cache_range_end) + return h; + while (pc >= h->end_pc) + { + cache_next_child = h->next_sibling; + h = h->outer; + } + } + else + { + h = &whole_range; + cache_next_child = h->first_child; + } + return find_handler_in_range (pc, h, cache_next_child); +} + +#if 0 +first_child; +next_sibling; +outer; +#endif + +/* Recursive helper routine for add_handler. */ + +static int +link_handler (start_pc, end_pc, handler, type, outer) + int start_pc, end_pc; + tree handler; + tree type; + struct eh_range *outer; +{ + struct eh_range **ptr; + if (start_pc < outer->start_pc || end_pc > outer->end_pc) + return 0; /* invalid or non-nested exception range */ + if (start_pc == outer->start_pc && end_pc == outer->end_pc) + { + outer->handlers = tree_cons (type, handler, outer->handlers); + return 1; + } + ptr = &outer->first_child; + for (;; ptr = &(*ptr)->next_sibling) + { + if (*ptr == NULL || end_pc <= (*ptr)->start_pc) + { + struct eh_range *h = (struct eh_range *) + oballoc (sizeof (struct eh_range)); + h->start_pc = start_pc; + h->end_pc = end_pc; + h->next_sibling = *ptr; + h->first_child = NULL; + h->outer = outer; + h->handlers = build_tree_list (type, handler); + *ptr = h; + return 1; + } + else if (start_pc < (*ptr)->end_pc) + return link_handler (start_pc, end_pc, handler, type, *ptr); + /* end_pc > (*ptr)->start_pc && start_pc >= (*ptr)->end_pc. */ + } +} + +/* Called to re-initialize the exception machinery for a new method. */ + +void +method_init_exceptions () +{ + whole_range.start_pc = 0; + whole_range.end_pc = DECL_CODE_LENGTH (current_function_decl) + 1; + whole_range.outer = NULL; + whole_range.first_child = NULL; + whole_range.next_sibling = NULL; + cache_range_start = 0xFFFFFF; + set_exception_lang_code (EH_LANG_Java); + set_exception_version_code (1); +} + +int +add_handler (start_pc, end_pc, handler, type) + int start_pc, end_pc; + tree handler; + tree type; +{ + return link_handler (start_pc, end_pc, handler, type, &whole_range); +} + + +/* if there are any handlers for this range, issue start of region */ +void +expand_start_java_handler (range) + struct eh_range *range; +{ + expand_eh_region_start (); +} + +/* if there are any handlers for this range, isssue end of range, + and then all handler blocks */ +void +expand_end_java_handler (range) + struct eh_range *range; +{ + tree handler = range->handlers; + expand_start_all_catch (); + for ( ; handler != NULL_TREE; handler = TREE_CHAIN (handler)) + { + tree type = TREE_PURPOSE (handler); + tree exp; + /* The "type" (metch_info) in a (Java) exception table is one: + * a) NULL - meaning match any type in a try-finally. + * b) a pointer to a (ccmpiled) class (low-order bit 0). + * c) a pointer to the Utf8Const name of the class, plus one + * (which yields a value with low-order bit 1). */ + push_obstacks (&permanent_obstack, &permanent_obstack); + if (type == NULL_TREE) + exp = null_pointer_node; + else if (is_compiled_class (type)) + exp = build_class_ref (type); + else + exp = fold (build (PLUS_EXPR, ptr_type_node, + build_utf8_ref (build_internal_class_name (type)), + size_one_node)); + pop_obstacks (); + start_catch_handler (exp); + expand_goto (TREE_VALUE (handler)); + } + expand_end_all_catch (); +} + +/* Recursive helper routine for maybe_start_handlers. */ + +static void +check_start_handlers (range, pc) + struct eh_range *range; + int pc; +{ + if (range != NULL_EH_RANGE && range->start_pc == pc) + { + check_start_handlers (range->outer, pc); + expand_start_java_handler (range); + } +} + +struct eh_range *current_range; + +/* Emit any start-of-try-range start at PC. */ + +void +maybe_start_try (pc) + int pc; +{ + if (! doing_eh (1)) + return; + + current_range = find_handler (pc); + check_start_handlers (current_range, pc); +} + +/* Emit any end-of-try-range end at PC. */ + +void +maybe_end_try (pc) + int pc; +{ + if (! doing_eh (1)) + return; + + while (current_range != NULL_EH_RANGE && current_range->end_pc <= pc) + { + expand_end_java_handler (current_range); + current_range = current_range->outer; + } +} + +/* Emit the handler labels and their code */ + +void +emit_handlers () +{ + if (catch_clauses) + { + rtx funcend = gen_label_rtx (); + emit_jump (funcend); + + emit_insns (catch_clauses); + expand_leftover_cleanups (); + + emit_label (funcend); + } +} diff --git a/gcc/java/expr.c b/gcc/java/expr.c new file mode 100644 index 00000000000..2c204da534f --- /dev/null +++ b/gcc/java/expr.c @@ -0,0 +1,2283 @@ +/* Process expressions for the GNU compiler for the Java(TM) language. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Hacked by Per Bothner February 1996. */ + +#include +#include "config.h" +#include "tree.h" +#include "real.h" +#include "rtl.h" +#include "expr.h" +#include "java-tree.h" +#include "javaop.h" +#include "java-opcodes.h" +#include "jcf.h" +#include "java-except.h" +#include "parse.h" + +static tree operand_type[59]; +extern struct obstack permanent_obstack; + +void +init_expr_processing() +{ + operand_type[21] = operand_type[54] = int_type_node; + operand_type[22] = operand_type[55] = long_type_node; + operand_type[23] = operand_type[56] = float_type_node; + operand_type[24] = operand_type[57] = double_type_node; + operand_type[25] = operand_type[58] = ptr_type_node; +} + +/* We store the stack state in two places: + Within a basic block, we use the quick_stack, which is a + pushdown list (TREE_LISTs) of expression nodes. + This is the top part of the stack; below that we use find_stack_slot. + At the end of a basic block, the quick_stack must be flushed + to the stack slot array (as handled by find_stack_slot). + Using quick_stack generates better code (especially when + compiled without optimization), because we do not have to + explicitly store and load trees to temporary variables. + + If a variable is on the quick stack, it means the value of variable + when the quick stack was last flushed. Conceptually, flush_quick_stack + saves all the the quick_stack elements in parellel. However, that is + complicated, so it actually saves them (i.e. copies each stack value + to is home virtual register) from low indexes. This allows a quick_stack + element at index i (counting from the bottom of stack the) to references + slot virtuals for register that are >= i, but not those that are deeper. + This convention makes most operations easier. For example iadd works + even when the stack contains (reg[0], reg[1]): It results in the + stack containing (reg[0]+reg[1]), which is OK. However, some stack + operations are more complicated. For example dup given a stack + containing (reg[0]) would yield (reg[0], reg[0]), which would violate + the convention, since stack value 1 would refer to a register with + lower index (reg[0]), which flush_quick_stack does not safely handle. + So dup cannot just add an extra element to the quick_stack, but iadd can. +*/ + +tree quick_stack = NULL_TREE; + +/* A free-list of unused permamnet TREE_LIST nodes. */ +tree tree_list_free_list = NULL_TREE; + +/* The stack pointer of the Java virtual machine. + This does include the size of the quick_stack. */ + +int stack_pointer; + +unsigned char *linenumber_table; +int linenumber_count; + +tree +truthvalue_conversion (expr) + tree expr; +{ + /* It is simpler and generates better code to have only TRUTH_*_EXPR + or comparison expressions as truth values at this level. + + This function should normally be identity for Java. */ + + switch (TREE_CODE (expr)) + { + case EQ_EXPR: + case NE_EXPR: case LE_EXPR: case GE_EXPR: case LT_EXPR: case GT_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case TRUTH_AND_EXPR: + case TRUTH_OR_EXPR: + case ERROR_MARK: + return expr; + + case INTEGER_CST: + return integer_zerop (expr) ? boolean_false_node : boolean_true_node; + + case REAL_CST: + return real_zerop (expr) ? boolean_false_node : boolean_true_node; + + /* are these legal? XXX JH */ + case NEGATE_EXPR: + case ABS_EXPR: + case FLOAT_EXPR: + case FFS_EXPR: + /* These don't change whether an object is non-zero or zero. */ + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + + case COND_EXPR: + /* Distribute the conversion into the arms of a COND_EXPR. */ + return fold (build (COND_EXPR, boolean_type_node, TREE_OPERAND (expr, 0), + truthvalue_conversion (TREE_OPERAND (expr, 1)), + truthvalue_conversion (TREE_OPERAND (expr, 2)))); + + case NOP_EXPR: + /* If this is widening the argument, we can ignore it. */ + if (TYPE_PRECISION (TREE_TYPE (expr)) + >= TYPE_PRECISION (TREE_TYPE (TREE_OPERAND (expr, 0)))) + return truthvalue_conversion (TREE_OPERAND (expr, 0)); + /* fall through to default */ + + default: + return fold (build (NE_EXPR, boolean_type_node, expr, boolean_false_node)); + } +} + +#ifdef JAVA_USE_HANDLES +/* Given a pointer to a handle, get a pointer to an object. */ + +tree +unhand_expr (expr) + tree expr; +{ + tree field, handle_type; + expr = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (expr)), expr); + handle_type = TREE_TYPE (expr); + field = TYPE_FIELDS (handle_type); + expr = build (COMPONENT_REF, TREE_TYPE (field), expr, field); + return expr; +} +#endif + +/* Save any stack slots that happen to be in the quick_stack into their + home virtual register slots. + + The copy order is from low stack index to high, to support the invariant + that the expression for a slot may contain decls for stack slots with + higher (or the same) index, but not lower. */ + +void +flush_quick_stack () +{ + int stack_index = stack_pointer; + register tree prev, cur, next; + + /* First reverse the quick_stack, and count the number of slots it has. */ + for (cur = quick_stack, prev = NULL_TREE; cur != NULL_TREE; cur = next) + { + next = TREE_CHAIN (cur); + TREE_CHAIN (cur) = prev; + prev = cur; + stack_index -= 1 + TYPE_IS_WIDE (TREE_TYPE (TREE_VALUE (cur))); + } + quick_stack = prev; + + while (quick_stack != NULL_TREE) + { + tree decl; + tree node = quick_stack, type; + quick_stack = TREE_CHAIN (node); + TREE_CHAIN (node) = tree_list_free_list; + tree_list_free_list = node; + node = TREE_VALUE (node); + type = TREE_TYPE (node); + + decl = find_stack_slot (stack_index, type); + if (decl != node) + expand_assignment (decl, node, 0, 0); + stack_index += 1 + TYPE_IS_WIDE (type); + } +} + +void +push_type (type) + tree type; +{ + int n_words; + type = promote_type (type); + n_words = 1 + TYPE_IS_WIDE (type); + if (stack_pointer + n_words > DECL_MAX_STACK (current_function_decl)) + fatal ("stack overflow"); + stack_type_map[stack_pointer++] = type; + n_words--; + while (--n_words >= 0) + stack_type_map[stack_pointer++] = TYPE_SECOND; +} + +void +push_value (value) + tree value; +{ + tree type = TREE_TYPE (value); + if (TYPE_PRECISION (type) < 32 && INTEGRAL_TYPE_P (type)) + { + type = promote_type (type); + value = convert (type, value); + } + push_type (type); + if (tree_list_free_list == NULL_TREE) + quick_stack = perm_tree_cons (NULL_TREE, value, quick_stack); + else + { + tree node = tree_list_free_list; + tree_list_free_list = TREE_CHAIN (tree_list_free_list); + TREE_VALUE (node) = value; + TREE_CHAIN (node) = quick_stack; + quick_stack = node; + } +} + +tree +pop_type (type) + tree type; +{ + int n_words; + int i; + tree t; + if (TREE_CODE (type) == RECORD_TYPE) + type = promote_type (type); + n_words = 1 + TYPE_IS_WIDE (type); + if (stack_pointer < n_words) + fatal ("stack underflow"); + while (--n_words > 0) + { + if (stack_type_map[--stack_pointer] != void_type_node) + fatal ("Invalid multi-word value on type stack"); + } + t = stack_type_map[--stack_pointer]; + if (type == NULL_TREE || t == type) + return t; + if (INTEGRAL_TYPE_P (type) && INTEGRAL_TYPE_P (t) + && TYPE_PRECISION (type) <= 32 && TYPE_PRECISION (t) <= 32) + return t; + if (TREE_CODE (type) == POINTER_TYPE && TREE_CODE (t) == POINTER_TYPE) + { + if (type == ptr_type_node || type == object_ptr_type_node) + return t; + else if (t == ptr_type_node) /* Special case for null reference. */ + return type; + else if (can_widen_reference_to (t, type)) + return t; + } + error ("unexpected type on stack"); + return t; +} + +/* Return 1f if SOURCE_TYPE can be safely widened to TARGET_TYPE. + Handles array types and interfaces. */ + +int +can_widen_reference_to (source_type, target_type) + tree source_type, target_type; +{ + if (source_type == ptr_type_node || target_type == object_ptr_type_node) + return 1; + + /* Get rid of pointers */ + if (TREE_CODE (source_type) == POINTER_TYPE) + source_type = TREE_TYPE (source_type); + if (TREE_CODE (target_type) == POINTER_TYPE) + target_type = TREE_TYPE (target_type); + + if (source_type == target_type) + return 1; + else + { + source_type = HANDLE_TO_CLASS_TYPE (source_type); + target_type = HANDLE_TO_CLASS_TYPE (target_type); + if (TYPE_ARRAY_P (source_type) || TYPE_ARRAY_P (target_type)) + { + HOST_WIDE_INT source_length, target_length; + if (TYPE_ARRAY_P (source_type) != TYPE_ARRAY_P (target_type)) + return 0; + target_length = java_array_type_length (target_type); + if (target_length >= 0) + { + source_length = java_array_type_length (source_type); + if (source_length != target_length) + return 0; + } + source_type = TYPE_ARRAY_ELEMENT (source_type); + target_type = TYPE_ARRAY_ELEMENT (target_type); + if (source_type == target_type) + return 1; + if (TREE_CODE (source_type) != POINTER_TYPE + || TREE_CODE (target_type) != POINTER_TYPE) + return 0; + return can_widen_reference_to (source_type, target_type); + } + else + { + int source_depth = class_depth (source_type); + int target_depth = class_depth (target_type); + + if (CLASS_INTERFACE (TYPE_NAME (target_type))) + { + /* target_type is OK if source_type or source_type ancestors + implement target_type. We handle multiple sub-interfaces */ + + tree basetype_vec = TYPE_BINFO_BASETYPES (source_type); + int n = TREE_VEC_LENGTH (basetype_vec), i; + for (i=0 ; i < n; i++) + if (can_widen_reference_to + (TREE_TYPE (TREE_VEC_ELT (basetype_vec, i)), + target_type)) + return 1; + if (n == 0) + return 0; + } + + for ( ; source_depth > target_depth; source_depth--) + { + source_type = TYPE_BINFO_BASETYPE (source_type, 0); + } + return source_type == target_type; + } + } +} + +tree +pop_value (type) + tree type; +{ + int n_words = 1 + TYPE_IS_WIDE (type); + int i; + type = pop_type (type); + if (quick_stack) + { + tree node = quick_stack; + quick_stack = TREE_CHAIN (quick_stack); + TREE_CHAIN (node) = tree_list_free_list; + tree_list_free_list = node; + node = TREE_VALUE (node); + return node; + } + else + return find_stack_slot (stack_pointer, promote_type (type)); +} + + +/* Pop and discrad the top COUNT stack slots. */ + +void +java_stack_pop (count) + int count; +{ + while (count > 0) + { + tree type, val; + if (stack_pointer == 0) + fatal ("stack underflow"); + type = stack_type_map[stack_pointer - 1]; + if (type == TYPE_SECOND) + { + count--; + if (stack_pointer == 1 || count <= 0) + fatal ("stack underflow"); + type = stack_type_map[stack_pointer - 2]; + } + val = pop_value (type); + count--; + } +} + +/* Implement the 'swap' operator (to swap two top stack slots). */ + +void +java_stack_swap () +{ + tree type1, type2; + rtx temp; + tree decl1, decl2; + + if (stack_pointer < 2 + || (type1 = stack_type_map[stack_pointer - 1]) == TYPE_UNKNOWN + || (type2 = stack_type_map[stack_pointer - 2]) == TYPE_UNKNOWN + || type1 == TYPE_SECOND || type2 == TYPE_SECOND + || TYPE_IS_WIDE (type1) || TYPE_IS_WIDE (type2)) + fatal ("bad stack swap"); + + flush_quick_stack (); + decl1 = find_stack_slot (stack_pointer - 1, type1); + decl2 = find_stack_slot (stack_pointer - 2, type2); + temp = copy_to_reg (DECL_RTL (decl1)); + emit_move_insn (DECL_RTL (decl1), DECL_RTL (decl2)); + emit_move_insn (DECL_RTL (decl2), temp); + stack_type_map[stack_pointer - 1] = type2; + stack_type_map[stack_pointer - 2] = type1; +} + +void +java_stack_dup (size, offset) + int size, offset; +{ + int low_index = stack_pointer - size - offset; + int dst_index; + if (low_index < 0) + error ("stack underflow - dup* operation"); + + flush_quick_stack (); + + stack_pointer += size; + dst_index = stack_pointer; + + for (dst_index = stack_pointer; --dst_index >= low_index; ) + { + tree type; + int src_index = dst_index - size; + if (src_index < low_index) + src_index = dst_index + size + offset; + type = stack_type_map [src_index]; + if (type == TYPE_SECOND) + { + if (src_index <= low_index) + fatal ("dup operation splits 64-bit number"); + stack_type_map[dst_index] = type; + src_index--; dst_index--; + type = stack_type_map[src_index]; + if (! TYPE_IS_WIDE (type)) + fatal ("internal error - dup operation"); + } + else if (TYPE_IS_WIDE (type)) + fatal ("internal error - dup operation"); + if (src_index != dst_index) + { + tree src_decl = find_stack_slot (src_index, type); + tree dst_decl = find_stack_slot (dst_index, type); + emit_move_insn (DECL_RTL (dst_decl), DECL_RTL (src_decl)); + stack_type_map[dst_index] = type; + } + } +} + +/* Calls soft_athrow. Discard the contents of the value stack. */ + +tree +build_java_athrow (node) + tree node; +{ + tree call; + + call = build (CALL_EXPR, + void_type_node, + build_address_of (throw_node), + build_tree_list (NULL_TREE, node), + NULL_TREE); + TREE_SIDE_EFFECTS (call) = 1; + expand_expr_stmt (call); + java_stack_pop (stack_pointer); +} + +/* Implementation for jsr/ret */ + +void +build_java_jsr (where, ret) + tree where; + tree ret; +{ + tree ret_label = fold (build1 (ADDR_EXPR, return_address_type_node, ret)); + push_value (ret_label); + flush_quick_stack (); + expand_goto (where); + expand_label (ret); +} + +void +build_java_ret (location) + tree location; +{ + expand_computed_goto (location); +} + +/* Implementation of operations on array: new, load, store, length */ + +/* Array core info access macros */ + +#define JAVA_ARRAY_LENGTH_OFFSET(A) \ + size_binop (CEIL_DIV_EXPR, \ + (DECL_FIELD_BITPOS \ + (TREE_CHAIN (TYPE_FIELDS (TREE_TYPE (TREE_TYPE (A)))))), \ + size_int (BITS_PER_UNIT)) + +tree +decode_newarray_type (int atype) +{ + switch (atype) + { + case 4: return boolean_type_node; + case 5: return char_type_node; + case 6: return float_type_node; + case 7: return double_type_node; + case 8: return byte_type_node; + case 9: return short_type_node; + case 10: return int_type_node; + case 11: return long_type_node; + default: return NULL_TREE; + } +} + +/* Build a call to soft_badarrayindex(), the ArrayIndexOfBoundsException + exception handler. */ + +static tree +build_java_throw_out_of_bounds_exception () +{ + tree node = build (CALL_EXPR, int_type_node, + build_address_of (soft_badarrayindex_node), + NULL_TREE, NULL_TREE ); + TREE_SIDE_EFFECTS (node) = 1; /* Allows expansion within ANDIF */ + return (node); +} + +/* Return the length of an array. Doesn't perform any checking on the nature + or value of the array NODE. May be used to implement some bytecodes. */ + +tree +build_java_array_length_access (node) + tree node; +{ + tree type = TREE_TYPE (node); + HOST_WIDE_INT length; + if (!is_array_type_p (type)) + fatal ("array length on a non-array reference"); + length = java_array_type_length (type); + if (length >= 0) + return build_int_2 (length, 0); + return fold (build1 (INDIRECT_REF, + int_type_node, + fold (build (PLUS_EXPR, ptr_type_node, + node, + JAVA_ARRAY_LENGTH_OFFSET(node))))); +} + +/* Optionally checks an array against the NULL pointer, eventually throwing a + NullPointerException. It could replace signal handling, but tied to NULL. + ARG1: the pointer to check, ARG2: the expression to use if + the pointer is non-null and ARG3 the type that should be returned. */ + +tree +build_java_arraynull_check (node, expr, type) + tree node; + tree expr; + tree type; +{ +#if 0 + static int java_array_access_throws_null_exception = 0; + node = ???; + if (java_array_access_throws_null_exception) + return (build (COND_EXPR, + type, + build (EQ_EXPR, int_type_node, node, null_pointer_node), + build_java_athrow (node), expr )); + else +#endif + return (expr); +} + +static tree +java_array_data_offset (array) + tree array; +{ + tree array_type = TREE_TYPE (TREE_TYPE (array)); + tree data_fld = TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (array_type))); + if (data_fld == NULL_TREE) + return size_in_bytes (array_type); + else + return build_int_2 (TREE_INT_CST_LOW (DECL_FIELD_BITPOS (data_fld)) + / BITS_PER_UNIT, 0); +} + +/* Implement array indexing (either as l-value or r-value). + Returns a tree for ARRAY[INDEX], assume TYPE is the element type. + Optionally performs bounds checking and/or test to NULL. + At this point, ARRAY should have been verified as an array. */ + +tree +build_java_arrayaccess (array, type, index) + tree array, type, index; +{ + tree arith, node, throw = NULL_TREE; + + arith = fold (build (PLUS_EXPR, int_type_node, + java_array_data_offset (array), + fold (build (MULT_EXPR, int_type_node, + index, size_in_bytes(type))))); + + if (flag_bounds_check) + { + /* Generate: + * (unsigned jint) INDEX >= (unsigned jint) LEN + * && throw ArrayIndexOutOfBoundsException. + * Note this is equivalent to and more efficient than: + * INDEX < 0 || INDEX >= LEN && throw ... */ + tree test; + tree len = build_java_array_length_access (array); + TREE_TYPE (len) = unsigned_int_type_node; + test = fold (build (GE_EXPR, boolean_type_node, + convert (unsigned_int_type_node, index), + len)); + if (! integer_zerop (test)) + { + throw = build (TRUTH_ANDIF_EXPR, int_type_node, test, + build_java_throw_out_of_bounds_exception ()); + /* allows expansion within COMPOUND */ + TREE_SIDE_EFFECTS( throw ) = 1; + } + } + + node = build1 (INDIRECT_REF, type, + fold (build (PLUS_EXPR, ptr_type_node, + array, + (throw ? build (COMPOUND_EXPR, int_type_node, + throw, arith ) + : arith)))); + + return (fold (build_java_arraynull_check (array, node, type))); +} + +/* Makes sure that INDEXED_TYPE is appropriate. If not, make it from + ARRAY_NODE. This function is used to retrieve something less vague than + a pointer type when indexing the first dimension of something like [[. + May return a corrected type, if necessary, otherwise INDEXED_TYPE is + return unchanged. + As a side effect, it also makes sure that ARRAY_NODE is an array. */ + +static tree +build_java_check_indexed_type (array_node, indexed_type) + tree array_node; + tree indexed_type; +{ + tree elt_type; + + if (!is_array_type_p (TREE_TYPE (array_node))) + fatal ("array indexing on a non-array reference"); + + elt_type = (TYPE_ARRAY_ELEMENT (TREE_TYPE (TREE_TYPE (array_node)))); + + if (indexed_type == ptr_type_node ) + return promote_type (elt_type); + + /* BYTE/BOOLEAN store and load are used for both type */ + if (indexed_type == byte_type_node && elt_type == boolean_type_node ) + return boolean_type_node; + + if (indexed_type != elt_type ) + fatal ("type array element mismatch"); + else + return indexed_type; +} + +/* newarray triggers a call to soft_newarray. This function should be called + with an integer code (the type of array to create) and get from the stack + the size of the dimmension. */ + +tree +build_newarray (atype_value, length) + int atype_value; + tree length; +{ + tree type = build_java_array_type (decode_newarray_type (atype_value), + TREE_CODE (length) == INTEGER_CST + ? TREE_INT_CST_LOW (length) + : -1); + return build (CALL_EXPR, promote_type (type), + build_address_of (soft_newarray_node), + tree_cons (NULL_TREE, + build_int_2 (atype_value, 0), + build_tree_list (NULL_TREE, length)), + NULL_TREE); +} + +/* Generates anewarray from a given CLASS_TYPE. Gets from the stack the size + of the dimension. */ +/* Merge with build_newarray. FIXME. */ +tree +build_anewarray (class_type, length) + tree class_type; + tree length; +{ + tree type = build_java_array_type (promote_type (class_type), + TREE_CODE (length) == INTEGER_CST + ? TREE_INT_CST_LOW (length) + : -1); + return build (CALL_EXPR, promote_type (type), + build_address_of (soft_anewarray_node), + tree_cons (NULL_TREE, length, + tree_cons (NULL_TREE, build_class_ref (class_type), + build_tree_list (NULL_TREE, + null_pointer_node))), + NULL_TREE); +} + +/* Generates a call to multianewarray. multianewarray expects a class pointer, + a number of dimensions and the matching number of dimensions. The argument + list is NULL terminated. */ + +void +expand_java_multianewarray (class_type, ndim) + tree class_type; + int ndim; +{ + int i; + tree args = build_tree_list( NULL_TREE, null_pointer_node ); + + for( i = 0; i < ndim; i++ ) + args = tree_cons (NULL_TREE, pop_value (int_type_node), args); + + push_value (build (CALL_EXPR, + promote_type (class_type), + build_address_of (soft_multianewarray_node), + tree_cons (NULL_TREE, build_class_ref (class_type), + tree_cons (NULL_TREE, + build_int_2 (ndim, 0), args )), + NULL_TREE)); +} + +/* ARRAY[INDEX] <- RHS. build_java_check_indexed_type makes sure that + ARRAY is an array type. May expand some bound checking and NULL + pointer checking. RHS_TYPE_NODE we are going to store. In the case + of the CHAR/BYTE/BOOLEAN SHORT, the type popped of the stack is an + INT. In those cases, we make the convertion. + + if ARRAy is a reference type, the assignment is checked at run-time + to make sure that the RHS can be assigned to the array element + type. It is not necessary to generate this code if ARRAY is final. */ + +void +expand_java_arraystore (rhs_type_node) + tree rhs_type_node; +{ + tree rhs_node = pop_value ((INTEGRAL_TYPE_P (rhs_type_node) + && TYPE_PRECISION (rhs_type_node) <= 32) ? + int_type_node : rhs_type_node); + tree index = pop_value (int_type_node); + tree array = pop_value (ptr_type_node); + + rhs_type_node = build_java_check_indexed_type (array, rhs_type_node); + + flush_quick_stack (); + + index = save_expr (index); + array = save_expr (array); + + if (TREE_CODE (rhs_type_node) == POINTER_TYPE + && !CLASS_FINAL (TYPE_NAME (TREE_TYPE (rhs_type_node)))) + { + tree check = build (CALL_EXPR, void_type_node, + build_address_of (soft_checkarraystore_node), + tree_cons (NULL_TREE, array, + build_tree_list (NULL_TREE, rhs_node)), + NULL_TREE); + TREE_SIDE_EFFECTS (check) = 1; + expand_expr_stmt (check); + } + + expand_assignment (build_java_arrayaccess (array, + rhs_type_node, + index), + rhs_node, 0, 0); +} + +/* Expand the evaluation of ARRAY[INDEX]. build_java_check_indexed_type makes + sure that LHS is an array type. May expand some bound checking and NULL + pointer checking. + LHS_TYPE_NODE is the type of ARRAY[INDEX]. But in the case of CHAR/BYTE/ + BOOLEAN/SHORT, we push a promoted type back to the stack. +*/ + +void +expand_java_arrayload (lhs_type_node ) + tree lhs_type_node; +{ + tree load_node; + int convert; + tree index_node = pop_value (int_type_node); + tree array_node = pop_value (ptr_type_node); + + index_node = save_expr (index_node); + array_node = save_expr (array_node); + lhs_type_node = build_java_check_indexed_type (array_node, lhs_type_node); + + load_node = build_java_arrayaccess (array_node, + lhs_type_node, + index_node); + + if (INTEGRAL_TYPE_P (lhs_type_node) && TYPE_PRECISION (lhs_type_node) <= 32) + load_node = fold (build1 (NOP_EXPR, int_type_node, load_node)); + push_value (load_node); +} + +/* Expands .length. Makes sure that we deal with and array and may expand + a NULL check on the array object. */ + +void +expand_java_array_length () +{ + tree array = pop_value (ptr_type_node); + tree length = build_java_array_length_access (array); + + push_value (build_java_arraynull_check (array, length, int_type_node)); +} + +/* Emit code for the call to soft_monitor{enter,exit}. CALL can be either + soft_monitorenter_node or soft_monitorexit_node. */ + +tree +build_java_monitor (call, object) + tree call; + tree object; +{ + return (build (CALL_EXPR, + void_type_node, + build_address_of (call), + build_tree_list (NULL_TREE, object), + NULL_TREE)); +} + +/* Emit code for one of the PUSHC instructions. */ + +void +expand_java_pushc (ival, type) + int ival; + tree type; +{ + tree value; + if (type == ptr_type_node && ival == 0) + value = null_pointer_node; + else if (type == int_type_node || type == long_type_node) + { + value = build_int_2 (ival, ival < 0 ? -1 : 0); + TREE_TYPE (value) = type; + } + else if (type == float_type_node || type == double_type_node) + { + REAL_VALUE_TYPE x; +#ifdef REAL_ARITHMETIC + REAL_VALUE_FROM_INT (x, ival, 0, TYPE_MODE (type)); +#else + x = ival; +#endif + value = build_real (type, x); + } + else + fatal ("internal error in expand_java_pushc"); + push_value (value); +} + +void +expand_java_return (type) + tree type; +{ + if (type == void_type_node) + expand_null_return (); + else + { + tree retval = pop_value (type); + tree res = DECL_RESULT (current_function_decl); + retval = build (MODIFY_EXPR, TREE_TYPE (res), res, retval); + TREE_SIDE_EFFECTS (retval) = 1; + expand_return (retval); + } +} + +tree +build_address_of (value) + tree value; +{ + return build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (value)), value); +} + +void +expand_java_NEW (type) + tree type; +{ + if (! CLASS_LOADED_P (type)) + load_class (type, 1); + push_value (build (CALL_EXPR, promote_type (type), + build_address_of (alloc_object_node), + tree_cons (NULL_TREE, build_class_ref (type), + build_tree_list (NULL_TREE, + size_in_bytes (type))), + NULL_TREE)); +} + +void +expand_java_INSTANCEOF (type) + tree type; +{ + tree value = pop_value (object_ptr_type_node); + value = build (CALL_EXPR, TREE_TYPE (TREE_TYPE (soft_instanceof_node)), + build_address_of (soft_instanceof_node), + tree_cons (NULL_TREE, value, + build_tree_list (NULL_TREE, + build_class_ref (type))), + NULL_TREE); + push_value (value); +} + +void +expand_java_CHECKCAST (type) + tree type; +{ + tree value = pop_value (ptr_type_node); + value = build (CALL_EXPR, promote_type (type), + build_address_of (soft_checkcast_node), + tree_cons (NULL_TREE, build_class_ref (type), + build_tree_list (NULL_TREE, value)), + NULL_TREE); + push_value (value); +} + +void +expand_iinc (unsigned int local_var_index, int ival, int pc) +{ + tree local_var, res; + tree constant_value; + + flush_quick_stack (); + local_var = find_local_variable (local_var_index, int_type_node, pc); + constant_value = build_int_2 (ival, ival < 0 ? -1 : 0); + res = fold (build (PLUS_EXPR, int_type_node, local_var, constant_value)); + expand_assignment (local_var, res, 0, 0); +} + +tree +build_java_binop (op, type, arg1, arg2) + enum tree_code op; + tree type, arg1, arg2; +{ + tree mask; + switch (op) + { + case URSHIFT_EXPR: + { + tree u_type = unsigned_type (type); + arg1 = convert (u_type, arg1); + arg1 = build_java_binop (RSHIFT_EXPR, u_type, arg1, arg2); + return convert (type, arg1); + } + case LSHIFT_EXPR: + case RSHIFT_EXPR: + mask = build_int_2 (TYPE_PRECISION (TREE_TYPE (arg1)) - 1, 0); + arg2 = fold (build (BIT_AND_EXPR, int_type_node, arg2, mask)); + break; + + case COMPARE_L_EXPR: /* arg1 > arg2 ? 1 : arg1 == arg2 ? 0 : -1 */ + case COMPARE_G_EXPR: /* arg1 < arg2 ? -1 : arg1 == arg2 ? 0 : 1 */ + arg1 = save_expr (arg1); arg2 = save_expr (arg2); + { + tree ifexp1 = fold ( build (op == COMPARE_L_EXPR ? GT_EXPR : LT_EXPR, + boolean_type_node, arg1, arg2)); + tree ifexp2 = fold ( build (EQ_EXPR, boolean_type_node, arg1, arg2)); + tree second_compare = fold (build (COND_EXPR, int_type_node, + ifexp2, integer_zero_node, + op == COMPARE_L_EXPR + ? integer_negative_one_node + : integer_one_node)); + return fold (build (COND_EXPR, int_type_node, ifexp1, + op == COMPARE_L_EXPR ? integer_one_node + : integer_negative_one_node, + second_compare)); + } + case COMPARE_EXPR: + arg1 = save_expr (arg1); arg2 = save_expr (arg2); + { + tree ifexp1 = fold ( build (LT_EXPR, boolean_type_node, arg1, arg2)); + tree ifexp2 = fold ( build (GT_EXPR, boolean_type_node, arg1, arg2)); + tree second_compare = fold ( build (COND_EXPR, int_type_node, + ifexp2, integer_one_node, + integer_zero_node)); + return fold (build (COND_EXPR, int_type_node, + ifexp1, integer_negative_one_node, second_compare)); + } + + case TRUNC_MOD_EXPR: + if (TREE_CODE (type) == REAL_TYPE) + { + tree call; + if (type != double_type_node) + { + arg1 = convert (double_type_node, arg1); + arg2 = convert (double_type_node, arg2); + } + call = build (CALL_EXPR, double_type_node, + build_address_of (soft_fmod_node), + tree_cons (NULL_TREE, arg1, + build_tree_list (NULL_TREE, arg2)), + NULL_TREE); + if (type != double_type_node) + call = convert (type, call); + return call; + } + break; + +#if 0 /* not required */ + case PLUS_EXPR: + case MULT_EXPR: + case MINUS_EXPR: + case TRUNC_DIV_EXPR: + case RDIV_EXPR: +/* case REM_EXPR: */ + case BIT_AND_EXPR: + case BIT_IOR_EXPR: + case BIT_XOR_EXPR: + break; + default: + error ("unknown opcode"); + return error_mark_node; +#endif + + } + return fold (build (op, type, arg1, arg2)); +} + +void +expand_java_binop (type, op) + tree type; enum tree_code op; +{ + tree larg, rarg; + tree ltype = type; + tree rtype = type; + switch (op) + { + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case URSHIFT_EXPR: + rtype = int_type_node; + rarg = pop_value (rtype); + break; + default: + rarg = pop_value (rtype); + } + larg = pop_value (ltype); + push_value (build_java_binop (op, type, larg, rarg)); +} + +/* Lookup the field named NAME in *TYPEP or its super classes. + If not found, return NULL_TREE. + (If the *TYPEP is not found, return error_mark_node.) + If found, return the FIELD_DECL, and set *TYPEP to the + class containing the field. */ + +tree +lookup_field (typep, name) + tree *typep; + tree name; +{ + if (CLASS_P (*typep) && !CLASS_LOADED_P (*typep)) + { + load_class (*typep, 1); + if (TREE_CODE (TYPE_SIZE (*typep)) == ERROR_MARK) + return error_mark_node; + } + do + { + tree field; + for (field = TYPE_FIELDS (*typep); field; field = TREE_CHAIN (field)) + { + if (DECL_NAME (field) == name) + return field; + } + *typep = CLASSTYPE_SUPER (*typep); + } while (*typep); + return NULL_TREE; +} + +/* Look up the field named NAME in object SELF_VALUE, + which has class SELF_CLASS (a non-handle RECORD_TYPE). + SELF_VALUE is NULL_TREE if looking for a static field. */ + +tree +build_field_ref (self_value, self_class, name) + tree self_value, self_class, name; +{ + tree base_class = self_class; + tree field_decl = lookup_field (&base_class, name); + if (field_decl == NULL_TREE) + { + error ("field `%s' not found", IDENTIFIER_POINTER (name)); + return error_mark_node; + } + if (self_value == NULL_TREE) + { + return build_static_field_ref (field_decl); + } + else + { + tree base_handle_type = promote_type (base_class); + if (base_handle_type != TREE_TYPE (self_value)) + self_value = fold (build1 (NOP_EXPR, base_handle_type, self_value)); +#ifdef JAVA_USE_HANDLES + self_value = unhand_expr (self_value); +#endif + self_value = build1 (INDIRECT_REF, TREE_TYPE (TREE_TYPE (self_value)), + self_value); + return fold (build (COMPONENT_REF, TREE_TYPE (field_decl), + self_value, field_decl)); + } +} + +tree +lookup_label (pc) + int pc; +{ + tree name; + char buf[20]; + sprintf (buf, "LJpc=%d", pc); + name = get_identifier (buf); + if (IDENTIFIER_LOCAL_VALUE (name)) + return IDENTIFIER_LOCAL_VALUE (name); + else + { + /* The type of the address of a label is return_address_type_node. */ + tree decl = create_label_decl (name); + LABEL_PC (decl) = pc; + label_rtx (decl); + return pushdecl (decl); + } +} + +tree +create_label_decl (name) + tree name; +{ + tree decl; + push_obstacks (&permanent_obstack, &permanent_obstack); + decl = build_decl (LABEL_DECL, name, + TREE_TYPE (return_address_type_node)); + pop_obstacks (); + DECL_CONTEXT (decl) = current_function_decl; + DECL_IGNORED_P (decl) = 1; + return decl; +} + +/* This maps a bytecode offset (PC) to various flags. */ +char *instruction_bits; + +void +note_label (current_pc, target_pc) + int current_pc, target_pc; +{ + lookup_label (target_pc); + instruction_bits [target_pc] |= BCODE_JUMP_TARGET; +} + +/* Emit code to jump to TARGET_PC if VALUE1 CONDITION VALUE2, + where CONDITION is one of one the compare operators. */ + + +void +expand_compare (condition, value1, value2, target_pc) + enum tree_code condition; + tree value1, value2; + int target_pc; +{ + tree target = lookup_label (target_pc); + tree cond = fold (build (condition, boolean_type_node, value1, value2)); + expand_start_cond (truthvalue_conversion (cond), 0); + expand_goto (target); + expand_end_cond (); +} + +/* Emit code for a TEST-type opcode. */ + +void +expand_test (condition, type, target_pc) + enum tree_code condition; + tree type; + int target_pc; +{ + tree value1, value2; + flush_quick_stack (); + value1 = pop_value (type); + value2 = (type == ptr_type_node) ? null_pointer_node : integer_zero_node; + expand_compare (condition, value1, value2, target_pc); +} + +/* Emit code for a COND-type opcode. */ + +void +expand_cond (condition, type, target_pc) + enum tree_code condition; + tree type; + int target_pc; +{ + tree value1, value2; + flush_quick_stack (); + /* note: pop values in opposite order */ + value2 = pop_value (type); + value1 = pop_value (type); + /* Maybe should check value1 and value2 for type compatibility ??? */ + expand_compare (condition, value1, value2, target_pc); +} + +void +expand_java_goto (target_pc) + int target_pc; +{ + tree target_label = lookup_label (target_pc); + flush_quick_stack (); + expand_goto (target_label); +} + +void +expand_java_call (target_pc, return_address) + int target_pc, return_address; +{ + tree target_label = lookup_label (target_pc); + tree value = build_int_2 (return_address, return_address < 0 ? -1 : 0); + push_value (value); + flush_quick_stack (); + expand_goto (target_label); +} + +void +expand_java_ret (return_address) + tree return_address; +{ + warning ("ret instruction not implemented"); +#if 0 + tree target_label = lookup_label (target_pc); + flush_quick_stack (); + expand_goto (target_label); +#endif +} + +/* Recursive helper function to pop argument types during verifiation. */ + +void +pop_argument_types (arg_types) + tree arg_types; +{ + if (arg_types == NULL_TREE) + return; + if (TREE_CODE (arg_types) == TREE_LIST) + { + pop_argument_types (TREE_CHAIN (arg_types)); + pop_type (TREE_VALUE (arg_types)); + return; + } + abort (); +} + +tree +pop_arguments (arg_types) + tree arg_types; +{ + if (arg_types == NULL_TREE) + return NULL_TREE; + if (TREE_CODE (arg_types) == TREE_LIST) + { + tree tail = pop_arguments (TREE_CHAIN (arg_types)); + return tree_cons (NULL_TREE, pop_value (TREE_VALUE (arg_types)), tail); + } + abort (); +} + +/* Build an expression to initialize the class CLAS. + if EXPR is non-NULL, returns an expression to first call the initializer + (if it is needed) and then calls EXPR. */ + +tree +build_class_init (clas, expr) + tree clas, expr; +{ + tree init; + if (inherits_from_p (current_class, clas)) + return expr; + init = build (CALL_EXPR, void_type_node, + build_address_of (soft_initclass_node), + build_tree_list (NULL_TREE, build_class_ref (clas)), + NULL_TREE); + TREE_SIDE_EFFECTS (init) = 1; + if (expr != NULL_TREE) + { + expr = build (COMPOUND_EXPR, TREE_TYPE (expr), init, expr); + TREE_SIDE_EFFECTS (expr) = 1; + return expr; + } + return init; +} + +static tree methods_ident = NULL_TREE; +static tree ncode_ident = NULL_TREE; +tree dtable_ident = NULL_TREE; + +tree +build_known_method_ref (method, method_type, self_type, method_signature, arg_list) + tree method, method_type, self_type, method_signature, arg_list; +{ + tree func; + if (flag_emit_class_files) + return method; + else if (is_compiled_class (self_type)) + { + make_decl_rtl (method, NULL, 1); + func = build1 (ADDR_EXPR, method_ptr_type_node, method); + } + else + { + /* We don't know whether the method has been (statically) compiled. + Compile this code to get a reference to the method's code: + + SELF_TYPE->methods[METHOD_INDEX].ncode + + This is guaranteed to work (assuming SELF_TYPE has + been initialized), since if the method is not compiled yet, + its ncode points to a trampoline that forces compilation. */ + + int method_index = 0; + tree meth; + tree ref = build_class_ref (self_type); + ref = build1 (INDIRECT_REF, class_type_node, ref); + if (ncode_ident == NULL_TREE) + ncode_ident = get_identifier ("ncode"); + if (methods_ident == NULL_TREE) + methods_ident = get_identifier ("methods"); + ref = build (COMPONENT_REF, method_ptr_type_node, ref, + lookup_field (&class_type_node, methods_ident)); + for (meth = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (self_type)); + ; meth = TREE_CHAIN (meth)) + { + if (method == meth) + break; + if (meth == NULL_TREE) + fatal ("method '%s' not found in class", + IDENTIFIER_POINTER (DECL_NAME (method))); + method_index++; + } + method_index *= int_size_in_bytes (method_type_node); + ref = fold (build (PLUS_EXPR, method_ptr_type_node, + ref, build_int_2 (method_index, 0))); + ref = build1 (INDIRECT_REF, method_type_node, ref); + func = build (COMPONENT_REF, nativecode_ptr_type_node, + ref, + lookup_field (&method_type_node, ncode_ident)); + } + return func; +} + +tree +invoke_build_dtable (is_invoke_interface, arg_list) + int is_invoke_interface; + tree arg_list; +{ + tree dtable, objectref; + + TREE_VALUE (arg_list) = save_expr (TREE_VALUE (arg_list)); + + /* If we're dealing with interfaces and if the objectref + argument is an array then get the dispatch table of the class + Object rather than the one from the objectref. */ + objectref = (is_invoke_interface + && is_array_type_p (TREE_TYPE (TREE_VALUE (arg_list))) ? + object_type_node : TREE_VALUE (arg_list)); + + if (dtable_ident == NULL_TREE) + dtable_ident = get_identifier ("dtable"); + dtable = build1 (INDIRECT_REF, object_type_node, objectref ); + dtable = build (COMPONENT_REF, dtable_ptr_type, dtable, + lookup_field (&object_type_node, dtable_ident)); + + return dtable; +} + +tree +build_invokevirtual (dtable, method) + tree dtable, method; +{ + tree func; + tree nativecode_ptr_ptr_type_node + = build_pointer_type (nativecode_ptr_type_node); + int method_index = TREE_INT_CST_LOW (DECL_VINDEX (method)); + /* Add one to skip "class" field of dtable, and one to skip unused + vtable entry (for C++ compatibility). */ + method_index += 2; + method_index + *= int_size_in_bytes (nativecode_ptr_ptr_type_node); + func = fold (build (PLUS_EXPR, nativecode_ptr_ptr_type_node, + dtable, build_int_2 (method_index, 0))); + func = build1 (INDIRECT_REF, nativecode_ptr_type_node, func); + + return func; +} + +/* Expand one of the invoke_* opcodes. + OCPODE is the specific opcode. + METHOD_REF_INDEX is an index into the constant pool. + NARGS is the number of arguments, or -1 if not specified. */ + +void +expand_invoke (opcode, method_ref_index, nargs) + int opcode; + int method_ref_index; + int nargs; +{ + tree method_signature = COMPONENT_REF_SIGNATURE(¤t_jcf->cpool, method_ref_index); + tree method_name = COMPONENT_REF_NAME (¤t_jcf->cpool, method_ref_index); + tree self_type = get_class_constant + (current_jcf, COMPONENT_REF_CLASS_INDEX(¤t_jcf->cpool, method_ref_index)); + char *self_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type))); + tree call, func, method, arg_list, method_type; + + static tree class_ident = NULL_TREE; + + if (! CLASS_LOADED_P (self_type)) + { + load_class (self_type, 1); + if (TREE_CODE (TYPE_SIZE (self_type)) == ERROR_MARK) + fatal ("failed to find class '%s'", self_name); + } + + if (method_name == init_identifier_node) + method = lookup_java_constructor (CLASS_TO_HANDLE_TYPE (self_type), + method_signature); + else + method = lookup_java_method (CLASS_TO_HANDLE_TYPE (self_type), + method_name, method_signature); + if (method == NULL_TREE) + { + error ("Class '%s' has no method named '%s' matching signature '%s'", + self_name, + IDENTIFIER_POINTER (method_name), + IDENTIFIER_POINTER (method_signature)); + } + /* Invoke static can't invoke static/abstract method */ + else if (opcode == OPCODE_invokestatic) + { + if (!METHOD_STATIC (method)) + { + error ("invokestatic on non static method"); + method = NULL_TREE; + } + else if (METHOD_ABSTRACT (method)) + { + error ("invokestatic on abstract method"); + method = NULL_TREE; + } + } + else + { + if (METHOD_STATIC (method)) + { + error ("invoke[non-static] on static method"); + method = NULL_TREE; + } + } + + if (method == NULL_TREE) + { + method_type = get_type_from_signature (method_signature); + pop_arguments (TYPE_ARG_TYPES (method_type)); + if (opcode != OPCODE_invokestatic) + pop_type (self_type); + method_type = promote_type (TREE_TYPE (method_type)); + push_value (convert (method_type, integer_zero_node)); + return; + } + + method_type = TREE_TYPE (method); + arg_list = pop_arguments (TYPE_ARG_TYPES (method_type)); + flush_quick_stack (); + + if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial + && ! inherits_from_p (current_class, self_type)) + { /* FIXME probably not needed for invokespecial if done by NEW. */ + /* Ensure self_type is initialized. */ + func = build (CALL_EXPR, void_type_node, soft_initclass_node, + build_tree_list (NULL_TREE, + build_class_ref (self_type)), + NULL_TREE); + expand_expr_stmt (func); + } + + func = NULL_TREE; + if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial + || (opcode == OPCODE_invokevirtual + && (METHOD_FINAL (method) || CLASS_FINAL (TYPE_NAME (self_type))))) + func = build_known_method_ref (method, method_type, self_type, + method_signature, arg_list); + else + { + tree dtable = invoke_build_dtable (opcode == OPCODE_invokeinterface, + arg_list); + if (opcode == OPCODE_invokevirtual) + func = build_invokevirtual (dtable, method); + else + { + /* We expand invokeinterface here. soft_lookupinterfacemethod () will + ensure that the selected method exists, is public and not abstract + nor static. */ + + tree lookup_arg; + + if (class_ident == NULL_TREE) + class_ident = get_identifier ("class"); + + dtable = build1 (INDIRECT_REF, dtable_type, dtable); + dtable = build (COMPONENT_REF, class_ptr_type, dtable, + lookup_field (&dtable_type, class_ident)); + lookup_arg = build_tree_list (NULL_TREE, + build_utf8_ref (method_signature)); + lookup_arg = tree_cons (NULL_TREE, dtable, + tree_cons (NULL_TREE, + build_utf8_ref (method_name), + lookup_arg)); + func = build (CALL_EXPR, + ptr_type_node, + build_address_of (soft_lookupinterfacemethod_node), + lookup_arg, NULL_TREE); + } + } + func = build1 (NOP_EXPR, build_pointer_type (method_type), func); + call = build (CALL_EXPR, TREE_TYPE (method_type), func, arg_list, NULL_TREE); + TREE_SIDE_EFFECTS (call) = 1; + + if (opcode == OPCODE_invokestatic || opcode == OPCODE_invokespecial) + { /* FIXME probably not needed for invokespecial if done by NEW. */ + /* Ensure self_type is initialized. */ + call = build_class_init (self_type, call); + } + + if (TREE_CODE (TREE_TYPE (method_type)) == VOID_TYPE) + expand_expr_stmt (call); + else + { + push_value (call); + flush_quick_stack (); + } +} + + +/* Expand an operation to extract from or store into a field. + IS_STATIC is 1 iff the field is static. + IS_PUTTING is 1 for putting into a field; 0 for getting from the field. + FIELD_REF_INDEX is an index into the constant pool. */ + +void +expand_java_field_op (is_static, is_putting, field_ref_index) + int is_static; + int is_putting; + int field_ref_index; +{ + tree self_type = get_class_constant + (current_jcf, COMPONENT_REF_CLASS_INDEX (¤t_jcf->cpool, field_ref_index)); + char *self_name = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (self_type))); + tree field_name = COMPONENT_REF_NAME (¤t_jcf->cpool, field_ref_index); + tree field_signature = COMPONENT_REF_SIGNATURE (¤t_jcf->cpool, field_ref_index); + tree field_type = get_type_from_signature (field_signature); + tree new_value = is_putting ? pop_value (field_type) : NULL_TREE; + tree field_ref; + int is_error = 0; + tree field_decl = lookup_field (&self_type, field_name); + if (field_decl == error_mark_node) + { + is_error = 1; + } + else if (field_decl == NULL_TREE) + { + error ("Missing field '%s' in '%s'", + IDENTIFIER_POINTER (field_name), self_name); + is_error = 1; + } + else if (build_java_signature (TREE_TYPE (field_decl)) != field_signature) + { + error ("Mismatching signature for field '%s' in '%s'", + IDENTIFIER_POINTER (field_name), self_name); + is_error = 1; + } + field_ref = is_static ? NULL_TREE : pop_value (self_type); + if (is_error) + { + if (! is_putting) + push_value (convert (promote_type (field_type), integer_zero_node)); + flush_quick_stack (); + return; + } + + /* Inline references to java.lang.PRIMTYPE.TYPE. + In addition to being a useful (minor) optimization, + this is also needed to avoid circularities in the implementation + of these fields in libjava. */ + if (field_name == TYPE_identifier_node && ! is_putting + && field_type == class_type_node + && strncmp (self_name, "java.lang.", 10) == 0) + { + char *class_name = self_name+10; + tree typ; + if (strcmp(class_name, "Byte") == 0) + typ = byte_type_node; + else if (strcmp(class_name, "Short") == 0) + typ = short_type_node; + else if (strcmp(class_name, "Integer") == 0) + typ = int_type_node; + else if (strcmp(class_name, "Long") == 0) + typ = long_type_node; + else if (strcmp(class_name, "Float") == 0) + typ = float_type_node; + else if (strcmp(class_name, "Boolean") == 0) + typ = boolean_type_node; + else if (strcmp(class_name, "Char") == 0) + typ = char_type_node; + else if (strcmp(class_name, "Void") == 0) + typ = void_type_node; + else + typ = NULL_TREE; + if (typ != NULL_TREE) + { + push_value (build_class_ref (typ)); + return; + } + } + + field_ref = build_field_ref (field_ref, self_type, field_name); + if (is_static) + field_ref = build_class_init (self_type, field_ref); + if (is_putting) + { + flush_quick_stack (); + if (FIELD_FINAL (field_decl)) + { + if (DECL_CONTEXT (field_decl) != current_class) + error_with_decl (field_decl, + "assignment to final field `%s' not in field's class"); + else if (FIELD_STATIC (field_decl)) + { + if (DECL_NAME (current_function_decl) != clinit_identifier_node) + error_with_decl (field_decl, + "assignment to final static field `%s' not in class initializer"); + } + else + { + if (! DECL_CONSTRUCTOR_P (current_function_decl)) + error_with_decl (field_decl, + "assignment to final field `%s' not in constructor"); + } + } + expand_assignment (field_ref, new_value, 0, 0); + } + else + push_value (field_ref); +} + +void +load_type_state (label) + tree label; +{ + int i; + tree vec = LABEL_TYPE_STATE (label); + int cur_length = TREE_VEC_LENGTH (vec); + stack_pointer = cur_length - DECL_MAX_LOCALS(current_function_decl); + for (i = 0; i < cur_length; i++) + type_map [i] = TREE_VEC_ELT (vec, i); +} + +struct rtx_def * +java_lang_expand_expr (exp, target, tmode, modifier) + register tree exp; + rtx target; + enum machine_mode tmode; + enum expand_modifier modifier; +{ + register rtx op0; + tree type = TREE_TYPE (exp); + register enum machine_mode mode = TYPE_MODE (type); + int unsignedp = TREE_UNSIGNED (type); + + switch (TREE_CODE (exp)) + { + case BLOCK: + if (BLOCK_EXPR_BODY (exp)) + { + tree local; + struct rtx_def *to_return; + pushlevel (2); /* 2 and above */ + expand_start_bindings (0); + local = BLOCK_EXPR_DECLS (exp); + while (local) + { + tree next = TREE_CHAIN (local); + layout_decl (local, 0); + expand_decl (pushdecl (local)); + local = next; + } + to_return = + expand_expr (BLOCK_EXPR_BODY (exp), target, tmode, modifier); + poplevel (1, 1, 0); + expand_end_bindings (getdecls (), 1, 0); + return to_return; + } + break; + + default: + fatal ("Can't expand '%s' tree - java_lang_expand_expr", + tree_code_name [TREE_CODE (exp)]); + } +} + +void +expand_byte_code (jcf, method) + JCF *jcf; + tree method; +{ + int PC; + int i; + int saw_index; + unsigned char *linenumber_pointer; + struct eh_range *prev_eh_ranges = NULL_EH_RANGE; + struct eh_range *eh_ranges; + +#undef RET /* Defined by config/i386/i386.h */ +#undef AND /* Causes problems with opcodes for iand and land. */ +#undef PTR +#define BCODE byte_ops +#define BYTE_type_node byte_type_node +#define SHORT_type_node short_type_node +#define INT_type_node int_type_node +#define LONG_type_node long_type_node +#define CHAR_type_node char_type_node +#define PTR_type_node ptr_type_node +#define FLOAT_type_node float_type_node +#define DOUBLE_type_node double_type_node +#define VOID_type_node void_type_node + jint INT_temp; + unsigned char* byte_ops; + long length = DECL_CODE_LENGTH (method); + + stack_pointer = 0; + JCF_SEEK (jcf, DECL_CODE_OFFSET (method)); + byte_ops = jcf->read_ptr; + +#define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1) +#define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2) +#define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1) +#define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2) + +#define CHECK_PC_IN_RANGE(PC) 1 /* Already handled by verifier. */ + + instruction_bits = oballoc (length + 1); + bzero (instruction_bits, length + 1); + + /* We make an initial pass of the line number table, to note + which instructions have associated line number entries. */ + linenumber_pointer = linenumber_table; + for (i = 0; i < linenumber_count; i++) + { + int pc = GET_u2 (linenumber_pointer); + linenumber_pointer += 4; + if (pc >= length) + warning ("invalid PC in line number table"); + else + { + if ((instruction_bits[pc] & BCODE_HAS_LINENUMBER) != 0) + instruction_bits[pc] |= BCODE_HAS_MULTI_LINENUMBERS; + instruction_bits[pc] |= BCODE_HAS_LINENUMBER; + } + } + + /* Do a preliminary pass. + * This figures out which PC can be the targets of jumps. */ + for (PC = 0; PC < length;) + { + int oldpc = PC; /* PC at instruction start. */ + instruction_bits [PC] |= BCODE_INSTRUCTION_START; + switch (byte_ops[PC++]) + { +#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \ + case OPCODE: \ + PRE_##OPKIND(OPERAND_TYPE, OPERAND_VALUE); \ + break; + +#define NOTE_LABEL(PC) note_label(oldpc, PC) + +#define PRE_PUSHC(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE); +#define PRE_LOAD(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE); +#define PRE_STORE(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE); +#define PRE_STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define PRE_UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define PRE_BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define PRE_CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define PRE_CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ + +#define PRE_SPECIAL(OPERAND_TYPE, INSTRUCTION) \ + PRE_SPECIAL_##INSTRUCTION(OPERAND_TYPE) +#define PRE_SPECIAL_IINC(OPERAND_TYPE) \ + ((void) IMMEDIATE_u1, (void) IMMEDIATE_s1) +#define PRE_SPECIAL_ENTER(IGNORE) /* nothing */ +#define PRE_SPECIAL_EXIT(IGNORE) /* nothing */ +#define PRE_SPECIAL_THROW(IGNORE) /* nothing */ +#define PRE_SPECIAL_BREAK(IGNORE) /* nothing */ + +/* two forms of wide instructions */ +#define PRE_SPECIAL_WIDE(IGNORE) \ + { \ + int modified_opcode = IMMEDIATE_u1; \ + if (modified_opcode == OPCODE_iinc) \ + { \ + (void) IMMEDIATE_u2; /* indexbyte1 and indexbyte2 */ \ + (void) IMMEDIATE_s2; /* constbyte1 and constbyte2 */ \ + } \ + else \ + { \ + (void) IMMEDIATE_u2; /* indexbyte1 and indexbyte2 */ \ + } \ + } + +/* nothing */ /* XXX JH */ + +#define PRE_IMPL(IGNORE1, IGNORE2) /* nothing */ + +#define PRE_MONITOR(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ + +#define PRE_RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define PRE_ARRAY(OPERAND_TYPE, SUBOP) \ + PRE_ARRAY_##SUBOP(OPERAND_TYPE) +#define PRE_ARRAY_LOAD(TYPE) /* nothing */ +#define PRE_ARRAY_STORE(TYPE) /* nothing */ +#define PRE_ARRAY_LENGTH(TYPE) /* nothing */ +#define PRE_ARRAY_NEW(TYPE) PRE_ARRAY_NEW_##TYPE +#define PRE_ARRAY_NEW_NUM ((void) IMMEDIATE_u1) +#define PRE_ARRAY_NEW_PTR ((void) IMMEDIATE_u2) +#define PRE_ARRAY_NEW_MULTI ((void) IMMEDIATE_u2, (void) IMMEDIATE_u1) + +#define PRE_TEST(OPERAND_TYPE, OPERAND_VALUE) NOTE_LABEL (oldpc+IMMEDIATE_s2) +#define PRE_COND(OPERAND_TYPE, OPERAND_VALUE) NOTE_LABEL (oldpc+IMMEDIATE_s2) +#define PRE_BRANCH(OPERAND_TYPE, OPERAND_VALUE) \ + saw_index = 0; INT_temp = (OPERAND_VALUE); \ + if (!saw_index) NOTE_LABEL(oldpc + INT_temp); +#define PRE_JSR(OPERAND_TYPE, OPERAND_VALUE) \ + saw_index = 0; INT_temp = (OPERAND_VALUE); \ + if (!saw_index) NOTE_LABEL(oldpc + INT_temp); + +#define PRE_RET(OPERAND_TYPE, OPERAND_VALUE) (void)(OPERAND_VALUE) + +#define PRE_SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \ + PC = (PC + 3) / 4 * 4; PRE_##TABLE_OR_LOOKUP##_SWITCH + +#define PRE_LOOKUP_SWITCH \ + { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \ + NOTE_LABEL (default_offset+oldpc); \ + if (npairs >= 0) \ + while (--npairs >= 0) { \ + jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \ + NOTE_LABEL (offset+oldpc); } \ + } + +#define PRE_TABLE_SWITCH \ + { jint default_offset = IMMEDIATE_s4; \ + jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \ + NOTE_LABEL (default_offset+oldpc); \ + if (low <= high) \ + while (low++ <= high) { \ + jint offset = IMMEDIATE_s4; \ + NOTE_LABEL (offset+oldpc); } \ + } + +#define PRE_FIELD(MAYBE_STATIC, PUT_OR_GET) (void)(IMMEDIATE_u2); +#define PRE_OBJECT(MAYBE_STATIC, PUT_OR_GET) (void)(IMMEDIATE_u2); +#define PRE_INVOKE(MAYBE_STATIC, IS_INTERFACE) \ + (void)(IMMEDIATE_u2); \ + PC += 2 * IS_INTERFACE /* for invokeinterface */; + +#include "javaop.def" +#undef JAVAOP + } + } /* for */ + + if (! verify_jvm_instructions (jcf, byte_ops, length)) + return; + + /* Translate bytecodes to rtl instructions. */ + linenumber_pointer = linenumber_table; + for (PC = 0; PC < length;) + { + if ((instruction_bits [PC] & BCODE_TARGET) != 0 || PC == 0) + { + tree label = lookup_label (PC); + flush_quick_stack (); + if ((instruction_bits [PC] & BCODE_TARGET) != 0) + expand_label (label); + if (LABEL_VERIFIED (label) || PC == 0) + load_type_state (label); + } + + if (! (instruction_bits [PC] & BCODE_VERIFIED)) + { + /* never executed - skip */ + warning ("Some bytecode operations (starting at pc %d) can never be executed", PC); + while (PC < length + && ! (instruction_bits [PC] & BCODE_VERIFIED)) + PC++; + continue; + } + + + /* Handle possible line number entry for this PC. + + This code handles out-of-order and multiple linenumbers per PC, + but is optimized for the case of line numbers increasing + monotonically with PC. */ + if ((instruction_bits[PC] & BCODE_HAS_LINENUMBER) != 0) + { + if ((instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS) != 0 + || GET_u2 (linenumber_pointer) != PC) + linenumber_pointer = linenumber_table; + while (linenumber_pointer < linenumber_table + linenumber_count * 4) + { + int pc = GET_u2 (linenumber_pointer); + linenumber_pointer += 4; + if (pc == PC) + { + lineno = GET_u2 (linenumber_pointer - 2); + emit_line_note (input_filename, lineno); + if (!(instruction_bits[PC] & BCODE_HAS_MULTI_LINENUMBERS)) + break; + } + } + } + maybe_start_try (PC); + maybe_pushlevels (PC); + + PC = process_jvm_instruction (PC, byte_ops, length); + + maybe_poplevels (PC); + maybe_end_try (PC); + } /* for */ +} + +void +java_push_constant_from_pool (jcf, index) + JCF *jcf; + int index; +{ + tree c; + if (JPOOL_TAG (jcf, index) == CONSTANT_String) + { + tree name; + push_obstacks (&permanent_obstack, &permanent_obstack); + name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); + index = alloc_name_constant (CONSTANT_String, name); + c = build_ref_from_constant_pool (index); + TREE_TYPE (c) = promote_type (string_type_node); + pop_obstacks (); + } + else + c = get_constant (jcf, index); + push_value (c); +} + +int +process_jvm_instruction (PC, byte_ops, length) + int PC; + unsigned char* byte_ops; + long length; +{ + char *opname; /* Temporary ??? */ + int oldpc = PC; /* PC at instruction start. */ + switch (byte_ops[PC++]) + { +#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \ + case OPCODE: \ + opname = #OPNAME; \ + OPKIND(OPERAND_TYPE, OPERAND_VALUE); \ + break; + +#define RET(OPERAND_TYPE, OPERAND_VALUE) \ + { \ + int saw_index = 0; \ + int index = OPERAND_VALUE; \ + build_java_ret (find_local_variable (index, ptr_type_node, oldpc)); \ + } + +#define JSR(OPERAND_TYPE, OPERAND_VALUE) \ + { \ + tree where = lookup_label (oldpc+OPERAND_VALUE); \ + tree ret = lookup_label (PC); \ + build_java_jsr (where, ret); \ + } + +/* Push a constant onto the stack. */ +#define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \ + { int saw_index = 0; int ival = (OPERAND_VALUE); \ + if (saw_index) java_push_constant_from_pool (current_jcf, ival); \ + else expand_java_pushc (ival, OPERAND_TYPE##_type_node); } + +/* internal macro added for use by the WIDE case */ +#define LOAD_INTERNAL(OPTYPE, OPVALUE) \ + push_value (find_local_variable (OPVALUE, type_map[OPVALUE], oldpc)); + +/* Push local variable onto the opcode stack. */ +#define LOAD(OPERAND_TYPE, OPERAND_VALUE) \ + { \ + /* have to do this since OPERAND_VALUE may have side-effects */ \ + int opvalue = OPERAND_VALUE; \ + LOAD_INTERNAL(OPERAND_TYPE##_type_node, opvalue); \ + } + +#define RETURN(OPERAND_TYPE, OPERAND_VALUE) \ + expand_java_return (OPERAND_TYPE##_type_node) + +#define REM_EXPR TRUNC_MOD_EXPR +#define BINOP(OPERAND_TYPE, OPERAND_VALUE) \ + expand_java_binop (OPERAND_TYPE##_type_node, OPERAND_VALUE##_EXPR) + +#define FIELD(IS_STATIC, IS_PUT) \ + expand_java_field_op (IS_STATIC, IS_PUT, IMMEDIATE_u2) + +#define TEST(OPERAND_TYPE, CONDITION) \ + expand_test (CONDITION##_EXPR, OPERAND_TYPE##_type_node, oldpc+IMMEDIATE_s2) + +#define COND(OPERAND_TYPE, CONDITION) \ + expand_cond (CONDITION##_EXPR, OPERAND_TYPE##_type_node, oldpc+IMMEDIATE_s2) + +#define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \ + BRANCH_##OPERAND_TYPE (OPERAND_VALUE) + +#define BRANCH_GOTO(OPERAND_VALUE) \ + expand_java_goto (oldpc + OPERAND_VALUE) + +#define BRANCH_CALL(OPERAND_VALUE) \ + expand_java_call (oldpc + OPERAND_VALUE, oldpc) + +#if 0 +#define BRANCH_RETURN(OPERAND_VALUE) \ + { \ + tree type = OPERAND_TYPE##_type_node; \ + tree value = find_local_variable (OPERAND_VALUE, type, oldpc); \ + expand_java_ret (value); \ + } +#endif + +#define NOT_IMPL(OPERAND_TYPE, OPERAND_VALUE) \ + fprintf (stderr, "%3d: %s ", oldpc, opname); \ + fprintf (stderr, "(not implemented)\n") +#define NOT_IMPL1(OPERAND_VALUE) \ + fprintf (stderr, "%3d: %s ", oldpc, opname); \ + fprintf (stderr, "(not implemented)\n") + +#define BRANCH_RETURN(OPERAND_VALUE) NOT_IMPL1(OPERAND_VALUE) + +#define STACK(SUBOP, COUNT) STACK_##SUBOP (COUNT) + +#define STACK_POP(COUNT) java_stack_pop (COUNT) + +#define STACK_SWAP(COUNT) java_stack_swap() + +#define STACK_DUP(COUNT) java_stack_dup (COUNT, 0) +#define STACK_DUPx1(COUNT) java_stack_dup (COUNT, 1) +#define STACK_DUPx2(COUNT) java_stack_dup (COUNT, 2) + +#define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \ + PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH + +#define LOOKUP_SWITCH \ + { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \ + tree selector = pop_value (INT_type_node); \ + tree duplicate, label; \ + tree type = TREE_TYPE (selector); \ + flush_quick_stack (); \ + expand_start_case (0, selector, type, "switch statement");\ + push_momentary (); \ + while (--npairs >= 0) \ + { \ + jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \ + tree value = build_int_2 (match, match < 0 ? -1 : 0); \ + TREE_TYPE (value) = type; \ + label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); \ + pushcase (value, convert, label, &duplicate); \ + expand_java_goto (oldpc + offset); \ + } \ + label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); \ + pushcase (NULL_TREE, 0, label, &duplicate); \ + expand_java_goto (oldpc + default_offset); \ + pop_momentary (); \ + expand_end_case (selector); \ + } + +#define TABLE_SWITCH \ + { jint default_offset = IMMEDIATE_s4; \ + jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \ + tree selector = pop_value (INT_type_node); \ + tree duplicate, label; \ + tree type = TREE_TYPE (selector); \ + flush_quick_stack (); \ + expand_start_case (0, selector, type, "switch statement");\ + push_momentary (); \ + for (; low <= high; low++) \ + { \ + jint offset = IMMEDIATE_s4; \ + tree value = build_int_2 (low, low < 0 ? -1 : 0); \ + TREE_TYPE (value) = type; \ + label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); \ + pushcase (value, convert, label, &duplicate); \ + expand_java_goto (oldpc + offset); \ + } \ + label = build_decl (LABEL_DECL, NULL_TREE, NULL_TREE); \ + pushcase (NULL_TREE, 0, label, &duplicate); \ + expand_java_goto (oldpc + default_offset); \ + pop_momentary (); \ + expand_end_case (selector); \ + } + +#define INVOKE(MAYBE_STATIC, IS_INTERFACE) \ + { int opcode = byte_ops[PC-1]; \ + int method_ref_index = IMMEDIATE_u2; \ + int nargs; \ + if (IS_INTERFACE) { nargs = IMMEDIATE_u1; (void) IMMEDIATE_u1; } \ + else nargs = -1; \ + expand_invoke (opcode, method_ref_index, nargs); \ + } + +/* Handle new, checkcast, instanceof */ +#define OBJECT(TYPE, OP) \ + expand_java_##OP (get_class_constant (current_jcf, IMMEDIATE_u2)) + +#define ARRAY(OPERAND_TYPE, SUBOP) ARRAY_##SUBOP(OPERAND_TYPE) + +#define ARRAY_LOAD(OPERAND_TYPE) \ + { \ + expand_java_arrayload( OPERAND_TYPE##_type_node ); \ + } + +#define ARRAY_STORE(OPERAND_TYPE) \ + { \ + expand_java_arraystore( OPERAND_TYPE##_type_node ); \ + } + +#define ARRAY_LENGTH(OPERAND_TYPE) expand_java_array_length(); +#define ARRAY_NEW(OPERAND_TYPE) ARRAY_NEW_##OPERAND_TYPE() +#define ARRAY_NEW_PTR() \ + push_value (build_anewarray (get_class_constant (current_jcf, \ + IMMEDIATE_u2), \ + pop_value (int_type_node))); +#define ARRAY_NEW_NUM() \ + { \ + int atype = IMMEDIATE_u1; \ + push_value (build_newarray (atype, pop_value (int_type_node)));\ + } +#define ARRAY_NEW_MULTI() \ + { \ + tree class = get_class_constant (current_jcf, IMMEDIATE_u2 ); \ + int ndims = IMMEDIATE_u1; \ + expand_java_multianewarray( class, ndims ); \ + } + +#define UNOP(OPERAND_TYPE, OPERAND_VALUE) \ + push_value (fold (build1 (NEGATE_EXPR, OPERAND_TYPE##_type_node, \ + pop_value (OPERAND_TYPE##_type_node)))); + +#define CONVERT2(FROM_TYPE, TO_TYPE) \ + { \ + push_value (build1 (NOP_EXPR, int_type_node, \ + (convert (TO_TYPE##_type_node, \ + pop_value (FROM_TYPE##_type_node))))); \ + } + +#define CONVERT(FROM_TYPE, TO_TYPE) \ + { \ + push_value (convert (TO_TYPE##_type_node, \ + pop_value (FROM_TYPE##_type_node))); \ + } + +/* internal macro added for use by the WIDE case + Added TREE_TYPE (decl) assignment, apbianco */ +#define STORE_INTERNAL(OPTYPE, OPVALUE) \ + { \ + tree decl, value; \ + int var = OPVALUE; \ + tree type = OPTYPE; \ + value = pop_value (type); \ + type = TREE_TYPE (value); \ + decl = find_local_variable (var, type, oldpc); \ + set_local_type (var, type ); \ + expand_assignment (decl, value, 0, 0); \ + } + +#define STORE(OPERAND_TYPE, OPERAND_VALUE) \ + { \ + /* have to do this since OPERAND_VALUE may have side-effects */ \ + int opvalue = OPERAND_VALUE; \ + STORE_INTERNAL(OPERAND_TYPE##_type_node, opvalue); \ + } + +#define SPECIAL(OPERAND_TYPE, INSTRUCTION) \ + SPECIAL_##INSTRUCTION(OPERAND_TYPE) + +#define SPECIAL_ENTER(IGNORED) MONITOR_OPERATION (soft_monitorenter_node) +#define SPECIAL_EXIT(IGNORED) MONITOR_OPERATION (soft_monitorexit_node) + +#define MONITOR_OPERATION(call) \ + { \ + tree o = pop_value (ptr_type_node); \ + tree c; \ + flush_quick_stack (); \ + c = build_java_monitor (call, o); \ + TREE_SIDE_EFFECTS (c) = 1; \ + expand_expr_stmt (c); \ + } + +#define SPECIAL_IINC(IGNORED) \ + { \ + unsigned int local_var_index = IMMEDIATE_u1; \ + int ival = IMMEDIATE_s1; \ + expand_iinc(local_var_index, ival, oldpc); \ + } + +#define SPECIAL_WIDE(IGNORED) \ + { \ + int modified_opcode = IMMEDIATE_u1; \ + unsigned int local_var_index = IMMEDIATE_u2; \ + switch (modified_opcode) \ + { \ + case OPCODE_iinc: \ + { \ + int ival = IMMEDIATE_s2; \ + expand_iinc (local_var_index, ival, oldpc); \ + break; \ + } \ + case OPCODE_iload: \ + case OPCODE_lload: \ + case OPCODE_fload: \ + case OPCODE_dload: \ + case OPCODE_aload: \ + { \ + /* duplicate code from LOAD macro */ \ + LOAD_INTERNAL(operand_type[modified_opcode], local_var_index); \ + break; \ + } \ + case OPCODE_istore: \ + case OPCODE_lstore: \ + case OPCODE_fstore: \ + case OPCODE_dstore: \ + case OPCODE_astore: \ + { \ + STORE_INTERNAL(operand_type[modified_opcode], local_var_index); \ + break; \ + } \ + default: \ + error ("unrecogized wide sub-instruction"); \ + } \ + } + +#define SPECIAL_THROW(IGNORED) \ + build_java_athrow (pop_value (throwable_type_node)) + +#define SPECIAL_BREAK NOT_IMPL1 +#define IMPL NOT_IMPL + +#include "javaop.def" +#undef JAVAOP + default: + fprintf (stderr, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]); + } + return PC; +} diff --git a/gcc/java/gjavah.c b/gcc/java/gjavah.c new file mode 100644 index 00000000000..875e9907dba --- /dev/null +++ b/gcc/java/gjavah.c @@ -0,0 +1,959 @@ +/* Program to write C++-suitable header files from a Java(TM) .class + file. This is similar to SUN's javah. + +Copyright (C) 1996, 1998 Free Software Foundation, Inc. + +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, 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 GNU CC; 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. */ + +/* Written by Per Bothner , February 1996. */ + +#include +#include "jcf.h" +#ifdef __STDC__ +#include +#endif +#include + +/* The output file. */ +FILE *out = NULL; + +/* Nonzero on failure. */ +static int found_error = 0; + +/* Directory to place resulting files in. Set by -d option. */ +char *output_directory = ""; + +char *output_file = NULL; + +/* Directory to place temporary file. Set by -td option. Currently unused. */ +char *temp_directory = "/tmp"; + +/* Number of friend functions we have to declare. */ +static int friend_count; + +/* A class can optionally have a `friend' function declared. If + non-NULL, this is that function. */ +static char **friend_specs = NULL; + +/* Number of lines we are prepending before the class. */ +static int prepend_count; + +/* We can prepend extra lines before the class's start. */ +static char **prepend_specs = NULL; + +/* Number of lines we are appending at the end of the class. */ +static int add_count; + +/* We can append extra lines just before the class's end. */ +static char **add_specs = NULL; + +/* Number of lines we are appending after the class. */ +static int append_count; + +/* We can append extra lines after the class's end. */ +static char **append_specs = NULL; + +int verbose = 0; + +int stubs = 0; + +struct JCF *current_jcf; +struct JCF *main_jcf; + +/* This holds access information for the last field we examined. They + let us generate "private:", "public:", and "protected:" properly. + If 0 then we haven't previously examined any field. */ +static JCF_u2 last_access; + +#define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED) + +int seen_fields = 0; + +static void print_field_info PROTO ((FILE *, JCF*, int, int, JCF_u2)); +static void print_method_info PROTO ((FILE *, JCF*, int, int, JCF_u2)); +static void print_c_decl PROTO ((FILE*, JCF*, int, int, JCF_u2, int)); + +JCF_u2 current_field_name; +JCF_u2 current_field_value; +JCF_u2 current_field_signature; +JCF_u2 current_field_flags; + +#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ +( current_field_name = (NAME), current_field_signature = (SIGNATURE), \ + current_field_flags = (ACCESS_FLAGS), current_field_value = 0) + +#define HANDLE_END_FIELD() \ + print_field_info (out, jcf, current_field_name, current_field_signature, \ + current_field_flags); + +#define HANDLE_CONSTANTVALUE(VALUEINDEX) current_field_value = (VALUEINDEX) + +#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ + print_method_info (out, jcf, NAME, SIGNATURE, ACCESS_FLAGS) + +#include "jcf-reader.c" + +/* Some useful constants. */ +#define F_NAN_MASK 0x7f800000 +#define D_NAN_MASK 0x7ff0000000000000LL + +/* Return 1 if F is not Inf or NaN. */ +static int +java_float_finite (f) + jfloat f; +{ + int32 *ip = (int32 *) &f; + + /* We happen to know that F_NAN_MASK will match all NaN values, and + also positive and negative infinity. That's why we only need one + test here. See The Java Language Specification, section 20.9. */ + return (*ip & F_NAN_MASK) != F_NAN_MASK; +} + +/* Return 1 if D is not Inf or NaN. */ +static int +java_double_finite (d) + jdouble d; +{ + int64 *ip = (int64 *) &d; + + /* Now check for all NaNs. */ + return (*ip & D_NAN_MASK) != D_NAN_MASK; +} + +void +DEFUN(print_name, (stream, jcf, name_index), + FILE* stream AND JCF* jcf AND int name_index) +{ + if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8) + fprintf (stream, ""); + else + jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf, name_index), + JPOOL_UTF_LENGTH (jcf, name_index)); +} + +/* Print base name of class. The base name is everything after the + final separator. */ + +static void +print_base_classname (stream, jcf, index) + FILE *stream; + JCF *jcf; + int index; +{ + int name_index = JPOOL_USHORT1 (jcf, index); + int i, len; + unsigned char *s, *p, *limit; + + s = JPOOL_UTF_DATA (jcf, name_index); + len = JPOOL_UTF_LENGTH (jcf, name_index); + limit = s + len; + p = s; + while (s < limit) + { + int c = UTF8_GET (s, limit); + if (c == '/') + p = s; + } + + while (p < limit) + { + int ch = UTF8_GET (p, limit); + if (ch == '/') + fputs ("::", stream); + else + jcf_print_char (stream, ch); + } +} + +/* Return 0 if NAME is equal to STR, nonzero otherwise. */ + +static int +utf8_cmp (str, length, name) + unsigned char *str; + int length; + char *name; +{ + unsigned char *limit = str + length; + int i; + + for (i = 0; name[i]; ++i) + { + int ch = UTF8_GET (str, limit); + if (ch != name[i]) + return 1; + } + + return str != limit; +} + +/* Generate an access control keyword based on FLAGS. Returns 0 if + FLAGS matches the saved access information, nonzero otherwise. */ + +static void +generate_access (stream, flags) + FILE *stream; + JCF_u2 flags; +{ + /* FIXME: Java's "protected" and "no access specifier" modes don't + actually map to C++ "protected". That's how we map them for now, + though. */ + + if (! (flags & ACC_VISIBILITY)) + flags = ACC_PROTECTED; + + if ((flags & ACC_VISIBILITY) == last_access) + return; + last_access = (flags & ACC_VISIBILITY); + + switch (last_access) + { + case ACC_PUBLIC: + fputs ("public:\n", stream); + break; + case ACC_PRIVATE: + fputs ("private:\n", stream); + break; + case ACC_PROTECTED: + fputs ("protected:\n", stream); + break; + default: + found_error = 1; + fprintf (stream, "#error unrecognized visibility %d\n", + (flags & ACC_VISIBILITY)); + break; + } +} + +static void +DEFUN(print_field_info, (stream, jcf, name_index, sig_index, flags), + FILE *stream AND JCF* jcf + AND int name_index AND int sig_index AND JCF_u2 flags) +{ + if (flags & ACC_FINAL) + { + if (current_field_value > 0) + { + jlong num; + char buffer[25]; + + generate_access (stream, flags); + switch (JPOOL_TAG (jcf, current_field_value)) + { + case CONSTANT_Integer: + fputs (" static const jint ", out); + print_name (out, jcf, name_index); + fputs (" = ", out); + num = JPOOL_INT (jcf, current_field_value); + format_int (buffer, num, 10); + fprintf (out, "%sL;\n", buffer); + break; + case CONSTANT_Long: + fputs (" static const jlong ", out); + print_name (out, jcf, name_index); + fputs (" = ", out); + num = JPOOL_LONG (jcf, current_field_value); + format_int (buffer, num, 10); + fprintf (out, "%sLL;\n", buffer); + break; + case CONSTANT_Float: + { + jfloat fnum = JPOOL_FLOAT (jcf, current_field_value); + fputs (" static const jfloat ", out); + print_name (out, jcf, name_index); + if (! java_float_finite (fnum)) + fputs (";\n", out); + else + fprintf (out, " = %.10g;\n", fnum); + } + break; + case CONSTANT_Double: + { + jdouble dnum = JPOOL_DOUBLE (jcf, current_field_value); + fputs (" static const jdouble ", out); + print_name (out, jcf, name_index); + if (! java_double_finite (dnum)) + fputs (";\n", out); + else + fprintf (out, " = %.17g;\n", dnum); + } + break; + default: + fprintf(out, " <>\n"); + } + + return; + } + } + + generate_access (stream, flags); + fputs (" ", out); + if (flags & ACC_STATIC) + fputs ("static ", out); + print_c_decl (out, jcf, name_index, sig_index, flags, 0); + fputs (";\n", out); + if (! (flags & ACC_STATIC)) + seen_fields++; +} + +static void +DEFUN(print_method_info, (stream, jcf, name_index, sig_index, flags), + FILE *stream AND JCF* jcf + AND int name_index AND int sig_index AND JCF_u2 flags) +{ + unsigned char *str; + int length, is_init = 0; + + if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8) + fprintf (stream, ""); + str = JPOOL_UTF_DATA (jcf, name_index); + length = JPOOL_UTF_LENGTH (jcf, name_index); + if (str[0] == '<') + { + /* Ignore internally generated methods like . However, + treat as a constructor. */ + if (! utf8_cmp (str, length, "")) + is_init = 1; + else + return; + } + + /* We can't generate a method whose name is a C++ reserved word. + For now the only problem has been `delete'; add more here as + required. FIXME: we need a better solution than just ignoring + the method. */ + if (! utf8_cmp (str, length, "delete")) + return; + + generate_access (stream, flags); + + fputs (" ", out); + if ((flags & ACC_STATIC)) + fputs ("static ", out); + else if (! (flags & ACC_FINAL) && ! (jcf->access_flags & ACC_FINAL)) + { + /* Don't print `virtual' if we have a constructor. */ + if (! is_init) + fputs ("virtual ", out); + } + print_c_decl (out, jcf, name_index, sig_index, flags, is_init); + + /* FIXME: it would be nice to decompile small methods here. That + would allow for inlining. */ + + fprintf(out, ";\n"); +} + +static void +DEFUN(print_c_decl, (stream, jcf, name_index, signature_index, flags, is_init), + FILE* stream AND JCF* jcf + AND int name_index AND int signature_index AND JCF_u2 flags + AND int is_init) +{ + if (JPOOL_TAG (jcf, signature_index) != CONSTANT_Utf8) + fprintf (stream, ""); + else + { + int length = JPOOL_UTF_LENGTH (jcf, signature_index); + unsigned char *str0 = JPOOL_UTF_DATA (jcf, signature_index); + register unsigned char *str = str0; + unsigned char *limit = str + length; + int j; + char *ctype; + int need_space = 0; + int is_method = str[0] == '('; + + if (is_method) + { + /* Skip to the return signature, and print that first. + However, don't do this is we are printing a construtcor. + */ + if (is_init) + { + str = str0 + 1; + /* FIXME: Most programmers love Celtic knots because + they see their own code in the interconnected loops. + That is, this is spaghetti. */ + goto have_constructor; + } + else + { + while (str < limit) + { + int ch = *str++; + if (ch == ')') + break; + } + } + } + + again: + while (str < limit) + { + switch (str[0]) + { + case '[': + for (str++; str < limit && *str >= '0' && *str <= '9'; str++) + ; + switch (*str) + { + case 'B': ctype = "jbyteArray"; goto printit; + case 'C': ctype = "jcharArray"; goto printit; + case 'D': ctype = "jdoubleArray"; goto printit; + case 'F': ctype = "jfloatArray"; goto printit; + case 'I': ctype = "jintArray"; goto printit; + case 'S': ctype = "jshortArray"; goto printit; + case 'J': ctype = "jlongArray"; goto printit; + case 'Z': ctype = "jbooleanArray"; goto printit; + case '[': ctype = "jobjectArray"; goto printit; + case 'L': + /* We have to generate a reference to JArray here, + so that our output matches what the compiler + does. */ + ++str; + fputs ("JArray<", out); + while (str < limit && *str != ';') + { + int ch = UTF8_GET (str, limit); + if (ch == '/') + fputs ("::", stream); + else + jcf_print_char (stream, ch); + } + fputs (" *> *", out); + need_space = 0; + ++str; + break; + default: + fprintf (stderr, "unparseable signature `%s'\n", str0); + found_error = 1; + ctype = "???"; goto printit; + } + break; + case '(': + fputc (*str++, stream); + continue; + case ')': + fputc (*str++, stream); + /* the return signature was printed in the first pass. */ + return; + case 'B': ctype = "jbyte"; goto printit; + case 'C': ctype = "jchar"; goto printit; + case 'D': ctype = "jdouble"; goto printit; + case 'F': ctype = "jfloat"; goto printit; + case 'I': ctype = "jint"; goto printit; + case 'J': ctype = "jlong"; goto printit; + case 'S': ctype = "jshort"; goto printit; + case 'Z': ctype = "jboolean"; goto printit; + case 'V': ctype = "void"; goto printit; + case 'L': + ++str; + while (*str && *str != ';') + { + int ch = UTF8_GET (str, limit); + if (ch == '/') + fputs ("::", stream); + else + jcf_print_char (stream, ch); + } + fputs (" *", stream); + if (*str == ';') + str++; + need_space = 0; + break; + default: + need_space = 1; + jcf_print_char (stream, *str++); + break; + printit: + str++; + need_space = 1; + fputs (ctype, stream); + break; + } + + if (is_method && str < limit && *str != ')') + fputs (", ", stream); + } + have_constructor: + if (name_index) + { + if (need_space) + fprintf (stream, " "); + /* Declare constructors specially. */ + if (is_init) + print_base_classname (stream, jcf, jcf->this_class); + else + print_name (stream, jcf, name_index); + } + if (is_method) + { + fputs (" (", stream); + /* Go to beginning, skipping '('. */ + str = str0 + 1; + goto again; /* To handle argument signatures. */ + } + } +} + +int +DEFUN(print_mangled_classname, (stream, jcf, prefix, index), + FILE *stream AND JCF *jcf AND char *prefix AND int index) +{ + int name_index = JPOOL_USHORT1 (jcf, index); + fputs (prefix, stream); + jcf_print_utf8_replace (out, + JPOOL_UTF_DATA (jcf, name_index), + JPOOL_UTF_LENGTH (jcf, name_index), + '/', '_'); +} + +/* Print PREFIX, then a class name in C++ format. If the name refers + to an array, ignore it and don't print PREFIX. Returns 1 if + something was printed, 0 otherwise. */ +static int +print_cxx_classname (stream, prefix, jcf, index) + FILE *stream; + char *prefix; + JCF *jcf; + int index; +{ + int name_index = JPOOL_USHORT1 (jcf, index); + int i, len, c; + unsigned char *s, *p, *limit; + + s = JPOOL_UTF_DATA (jcf, name_index); + len = JPOOL_UTF_LENGTH (jcf, name_index); + limit = s + len; + + /* Explicitly omit arrays here. */ + p = s; + c = UTF8_GET (p, limit); + if (c == '[') + return 0; + + fputs (prefix, stream); + while (s < limit) + { + c = UTF8_GET (s, limit); + if (c == '/') + fputs ("::", stream); + else + jcf_print_char (stream, c); + } + + return 1; +} + +int written_class_count = 0; + +/* Return name of superclass. If LEN is not NULL, fill it with length + of name. */ +static unsigned char * +super_class_name (derived_jcf, len) + JCF *derived_jcf; + int *len; +{ + int supername_index = JPOOL_USHORT1 (derived_jcf, derived_jcf->super_class); + int supername_length = JPOOL_UTF_LENGTH (derived_jcf, supername_index); + unsigned char *supername = JPOOL_UTF_DATA (derived_jcf, supername_index); + + if (len) + *len = supername_length; + + return supername; +} + +/* Print declarations for all classes required by this class. FIXME: + the current implementation just prints every class name from the + constant pool. This is too much. We really only need to print a + declaration for each class which is the type of a return value, a + field, or an argument. */ +static void +print_class_decls (out, jcf) + FILE *out; + JCF *jcf; +{ + int i, seen_one = 0; + + for (i = 1; i < JPOOL_SIZE (jcf); ++i) + { + int kind = JPOOL_TAG (jcf, i); + if (kind == CONSTANT_Class) + { + if (print_cxx_classname (out, "class ", jcf, i)) + fputs (";\n", out); + seen_one = 1; + } + } + + if (seen_one) + fputs ("\n", out); +} + +static void +DEFUN(process_file, (file, out), + JCF *jcf AND FILE *out) +{ + int code, i; + + current_jcf = main_jcf = jcf; + + last_access = 0; + + if (jcf_parse_preamble (jcf) != 0) + { + fprintf (stderr, "Not a valid Java .class file.\n"); + found_error = 1; + return; + } + + /* Parse and possibly print constant pool */ + code = jcf_parse_constant_pool (jcf); + if (code != 0) + { + fprintf (stderr, "error while parsing constant pool\n"); + found_error = 1; + return; + } + code = verify_constant_pool (jcf); + if (code > 0) + { + fprintf (stderr, "error in constant pool entry #%d\n", code); + found_error = 1; + return; + } + + jcf_parse_class (jcf); + + if (written_class_count++ == 0) + fputs ("// DO NOT EDIT THIS FILE - it is machine generated -*- c++ -*-\n\n", + out); + + print_mangled_classname (out, jcf, "#ifndef __", jcf->this_class); + fprintf (out, "__\n"); + + print_mangled_classname (out, jcf, "#define __", jcf->this_class); + fprintf (out, "__\n\n"); + + if (jcf->super_class) + { + int super_length; + unsigned char *supername = super_class_name (jcf, &super_length); + + fputs ("#include <", out); + jcf_print_utf8 (out, supername, super_length); + fputs (".h>\n", out); + + /* FIXME: If our superclass is Object, then we include + java-array.h. The right thing to do here is look at all the + methods and fields and see if an array is in use. Only then + would we need to include java-array.h. */ + if (! utf8_cmp (supername, super_length, "java/lang/Object")) + fputs ("#include \n", out); + + fputs ("\n", out); + } + + print_class_decls (out, jcf); + + for (i = 0; i < prepend_count; ++i) + fprintf (out, "%s\n", prepend_specs[i]); + if (prepend_count > 0) + fputc ('\n', out); + + if (! print_cxx_classname (out, "class ", jcf, jcf->this_class)) + { + fprintf (stderr, "class is of array type\n"); + found_error = 1; + return; + } + if (jcf->super_class) + { + if (! print_cxx_classname (out, " : public ", jcf, jcf->super_class)) + { + fprintf (stderr, "base class is of array type\n"); + found_error = 1; + return; + } + } + fputs ("\n{\n", out); + + /* We make a single pass over the file, printing methods and fields + as we see them. We have to list the methods in the same order + that they appear in the class file, so that the Java and C++ + vtables have the same layout. */ + jcf_parse_fields (jcf); + jcf_parse_methods (jcf); + jcf_parse_final_attributes (jcf); + + /* Generate friend decl if we still must. */ + for (i = 0; i < friend_count; ++i) + fprintf (out, " friend %s\n", friend_specs[i]); + + /* Generate extra declarations. */ + if (add_count > 0) + fputc ('\n', out); + for (i = 0; i < add_count; ++i) + fprintf (out, " %s\n", add_specs[i]); + + fputs ("};\n", out); + + if (append_count > 0) + fputc ('\n', out); + for (i = 0; i < append_count; ++i) + fprintf (out, "%s\n", append_specs[i]); + + print_mangled_classname (out, jcf, "\n#endif /* __", jcf->this_class); + fprintf (out, "__ */\n"); +} + +static void +usage () +{ + fprintf (stderr, "gjavah: no classes specified\n"); + exit (1); +} + +static void +help () +{ + printf ("Usage: gjavah [OPTION]... CLASS...\n\n"); + printf ("Generate C++ header files from .class files\n\n"); + printf (" --classpath PATH Set path to find .class files\n"); + printf (" -d DIRECTORY Set output directory name\n"); + printf (" --help Print this help, then exit\n"); + printf (" -o FILE Set output file name\n"); + printf (" -td DIRECTORY Set temporary directory name\n"); + printf (" -v, --verbose Print extra information while running\n"); + printf (" --version Print version number, then exit\n"); + /* FIXME: print bug-report information. */ + exit (0); +} + +static void +no_argument (opt) + char *opt; +{ + fprintf (stderr, "gjavah: no argument given for option `%s'\n", opt); + exit (1); +} + +static void +version () +{ + /* FIXME: use version.c? */ + printf ("gjavah (GNU gcc) 0.0\n\n"); + printf ("Copyright (C) 1998 Free Software Foundation, Inc.\n"); + printf ("This is free software; see the source for copying conditions. There is NO\n"); + printf ("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"); + exit (0); +} + +int +DEFUN(main, (argc, argv), + int argc AND char** argv) +{ + JCF jcf; + int argi; + + if (argc <= 1) + usage (); + + for (argi = 1; argi < argc; argi++) + { + char *arg = argv[argi]; + + if (arg[0] != '-' || ! strcmp (arg, "--")) + break; + + /* Just let all arguments be given in either "-" or "--" form. */ + if (arg[1] == '-') + ++arg; + + if (strcmp (arg, "-o") == 0) + { + if (argi + 1 < argc) + output_file = argv[++argi]; + else + no_argument (argv[argi]); + } + else if (strcmp (arg, "-d") == 0) + { + if (argi + 1 < argc) + output_directory = argv[++argi]; + else + no_argument (argv[argi]); + } + else if (strcmp (arg, "-td") == 0) + { + if (argi + 1 < argc) + temp_directory = argv[++argi]; + else + no_argument (argv[argi]); + } + else if (strcmp (arg, "-prepend") == 0) + { + if (argi + 1 < argc) + { + if (prepend_count == 0) + prepend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*)); + prepend_specs[prepend_count++] = argv[++argi]; + } + else + no_argument (argv[argi]); + } + else if (strcmp (arg, "-friend") == 0) + { + if (argi + 1 < argc) + { + if (friend_count == 0) + friend_specs = (char**) ALLOC ((argc-argi) * sizeof (char*)); + friend_specs[friend_count++] = argv[++argi]; + } + else + no_argument (argv[argi]); + } + else if (strcmp (arg, "-add") == 0) + { + if (argi + 1 < argc) + { + if (add_count == 0) + add_specs = (char**) ALLOC ((argc-argi) * sizeof (char*)); + add_specs[add_count++] = argv[++argi]; + } + else + no_argument (argv[argi]); + } + else if (strcmp (arg, "-append") == 0) + { + if (argi + 1 < argc) + { + if (append_count == 0) + append_specs = (char**) ALLOC ((argc-argi) * sizeof (char*)); + append_specs[append_count++] = argv[++argi]; + } + else + no_argument (argv[argi]); + } + else if (strcmp (arg, "-classpath") == 0) + { + if (argi + 1 < argc) + classpath = argv[++argi]; + else + no_argument (argv[argi]); + } + else if (strcmp (arg, "-verbose") == 0 || strcmp (arg, "-v") == 0) + verbose++; + else if (strcmp (arg, "-stubs") == 0) + stubs++; + else if (strcmp (arg, "-help") == 0) + help (); + else if (strcmp (arg, "-version") == 0) + version (); + else + { + fprintf (stderr, "%s: illegal argument\n", argv[argi]); + exit (1); + } + } + + if (argi == argc) + usage (); + + if (classpath == NULL) + { + classpath = (char *) getenv ("CLASSPATH"); + if (classpath == NULL) + classpath = ""; + } + + for (; argi < argc; argi++) + { + char *classname = argv[argi]; + char *classfile_name, *current_output_file; + + if (verbose) + fprintf (stderr, "Processing %s\n", classname); + classfile_name = find_class (classname, strlen (classname), &jcf, 1); + if (classfile_name == NULL) + { + fprintf (stderr, "%s: no such class\n", classname); + exit (1); + } + if (verbose) + fprintf (stderr, "Found in %s\n", classfile_name); + if (output_file) + { + if (strcmp (output_file, "-") == 0) + out = stdout; + else if (out == NULL) + out = fopen (output_file, "w"); + if (out == NULL) + { + perror (output_file); + exit (1); + } + current_output_file = output_file; + } + else + { + int dir_len = strlen (output_directory); + int i, classname_length = strlen (classname); + current_output_file = (char*) ALLOC (dir_len + classname_length + 4); + strcpy (current_output_file, output_directory); + if (dir_len > 0 && output_directory[dir_len-1] != '/') + current_output_file[dir_len++] = '/'; + for (i = 0; classname[i] != '\0'; i++) + { + char ch = classname[i]; + if (ch == '.') + ch = '/'; + current_output_file[dir_len++] = ch; + } + strcpy (current_output_file+dir_len, ".h"); + out = fopen (current_output_file, "w"); + if (out == NULL) + { + perror (current_output_file); + exit (1); + } + } + process_file (&jcf, out); + JCF_FINISH (&jcf); + if (current_output_file != output_file) + free (current_output_file); + } + + if (out != NULL && out != stdout) + fclose (out); + + return found_error; +} + +/* TODO: + + * Do whatever the javah -stubs flag does. + + * Emit "structure forward declarations" when needed. + + * Generate C headers, like javah + + */ diff --git a/gcc/java/java-except.h b/gcc/java/java-except.h new file mode 100644 index 00000000000..576096f8270 --- /dev/null +++ b/gcc/java/java-except.h @@ -0,0 +1,67 @@ +/* Definitions for exception handling for use by the GNU compiler + for the Java(TM) language compiler. + Copyright (C) 1997 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +struct eh_range + { + /* The (byte-code PC) range of the handled block. */ + int start_pc; + int end_pc; + + /* A list of handlers. For each element in the list, + the TREE_PURPOSE is the handled class (NULL_EXPR for a finally block), + and the TREE_VALUE is the LABEL_DECL of the handler. */ + tree handlers; + + /* Surrunding handler, if any. */ + struct eh_range *outer; + + /* The first child range. It is is nested inside this range + (i.e. this.start_pc <= first_child.end_pc + && this.end_pc >= first_child.end_pc). + The children are linked together using next_sibling, and are sorted + by increasing start_pc and end_pc (we do not support non-nested + overlapping ranges). */ + struct eh_range *first_child; + + /* The next child of outer, in address order. */ + struct eh_range *next_sibling; + +#if 0 + /* Next handler, sorted by ascending start_pc then descending end_pc. */ + tree next; +#endif + }; + +/* A dummy range that represents the entire method. */ +extern struct eh_range whole_range; + +#define NULL_EH_RANGE (&whole_range) + +extern struct eh_range * find_handler PROTO ((int)); + +extern void method_init_exceptions PROTO ((void)); + +extern void emit_handlers PROTO ((void)); + diff --git a/gcc/java/java-opcodes.h b/gcc/java/java-opcodes.h new file mode 100644 index 00000000000..8fbe55cb708 --- /dev/null +++ b/gcc/java/java-opcodes.h @@ -0,0 +1,5 @@ +enum java_opcode { +#define JAVAOP(NAME, CODE, KIND, TYPE, VALUE) OPCODE_##NAME = CODE, +#include "javaop.def" +#undef JAVAOP +}; diff --git a/gcc/java/java-tree.def b/gcc/java/java-tree.def new file mode 100644 index 00000000000..a05b92d0aac --- /dev/null +++ b/gcc/java/java-tree.def @@ -0,0 +1,12 @@ +/* Shift right, logical. */ + +DEFTREECODE (URSHIFT_EXPR, "urshift_expr", "2", 2) + +/* Return -1, 0, 1 depending on whether the first argument is + less, equal, or greater to the second argument. */ +DEFTREECODE (COMPARE_EXPR, "compare_expr", "2", 2) + +/* Same as COMPARE_EXPR, but if either value is NaN, the result is -1. */ +DEFTREECODE (COMPARE_L_EXPR, "compare_l_expr", "2", 2) +/* Same as COMPARE_EXPR, but if either value is NaN, the result is 1. */ +DEFTREECODE (COMPARE_G_EXPR, "compare_g_expr", "2", 2) diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h new file mode 100644 index 00000000000..d8084993bee --- /dev/null +++ b/gcc/java/java-tree.h @@ -0,0 +1,720 @@ +/* Definitions for parsing and type checking for the GNU compiler for + the Java(TM) language. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Hacked by Per Bothner February 1996. */ + +/* Java language-specific tree codes. */ +#define DEFTREECODE(SYM, NAME, TYPE, LENGTH) SYM, +enum java_tree_code { + __DUMMY = LAST_AND_UNUSED_TREE_CODE, +#include "java-tree.def" + LAST_JAVA_TREE_CODE +}; +#undef DEFTREECODE + +struct JCF; + +/* Usage of TREE_LANG_FLAG_?: + 0: IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (in IDENTIFIER_NODE) + RESOLVE_EXPRESSION_NAME_P (in EXPR_WITH_FILE_LOCATION) + IS_FOR_LOOP_P (in LOOP_EXPR) + 1: CLASS_HAS_SUPER_FLAG (in TREE_VEC). + IS_A_CLASSFILE_NAME (in IDENTIFIER_NODE) + COMPOUND_ASSIGN_P (in EXPR (binop_*)) + 2: RETURN_MAP_ADJUSTED (in TREE_VEC). + QUALIFIED_P (in IDENTIFIER_NODE) + PRIMARY_P (in EXPR_WITH_FILE_LOCATION) + MODIFY_EXPR_FROM_INITIALIZATION_P (in MODIFY_EXPR) + 3: IS_AN_IMPORT_ON_DEMAND_P (in IDENTIFIER_NODE) + RESOLVE_PACKAGE_NAME_P (in EXPR_WITH_FILE_LOCATION) + 4: RESOLVE_TYPE_NAME_P (in EXPR_WITH_FILE_LOCATION) + 5: IS_BREAK_STMT_P (in EXPR_WITH_FILE_LOCATION) + + Usage of TYPE_LANG_FLAG_?: + 1: TYPE_ARRAY_P (in RECORD_TYPE). + 2: CLASS_LOADED_P (in RECORD_TYPE). + 3: CLASS_FROM_SOURCE_P (in RECORD_TYPE). + 4: CLASS_P (in RECORD_TYPE). + + Usage of DECL_LANG_FLAG_?: + 1: METHOD_PUBLIC (in FUNCTION_DECL). + FIELD_PUBLIC (in FIELD_DECL). + CLASS_PUBLIC (in TYPE_DECL). + 2: METHOD_STATIC (in FUNCTION_DECL). + (But note that FIELD_STATIC uses TREE_STATIC!) + CLASS_COMPLETE_P (in TYPE_DECL) + 3: METHOD_FINAL (in FUNCTION_DECL) + FIELD_FINAL (in FIELD_DECL) + CLASS_FINAL (in TYPE_DECL) + 4: METHOD_SYNCHRONIZED (in FUNCTION_DECL). + LABEL_IN_SUBR (in LABEL_DECL) + CLASS_INTERFACE (in TYPE_DECL) + FIELD_VOLATILE (int FIELD_DECL) + 5: METHOD_ABSTRACT (in FUNCTION_DECL). + LABEL_IS_SUBR_START (in LABEL_DECL) + CLASS_ABSTRACT (in TYPE_DECL) + FIELD_TRANSIENT (in FIELD_DECL) + 6: METHOD_TRANSIENT (in FUNCTION_DECL) + LABEL_CHANGED (in LABEL_DECL) + CLASS_SUPER (in TYPE_DECL, ACC_SUPER flag) + INITIALIZED_P (in FIELD_DECL, VAR_DECL, PARM_DECL) + 7: DECL_CONSTRUCTOR_P (in FUNCTION_DECL) +*/ + +/* True if the class whose TYPE_BINFO this is has a superclass. + (True of all classes except Object.) */ +#define CLASS_HAS_SUPER_FLAG(BINFO) TREE_LANG_FLAG_1(BINFO) +#define CLASS_HAS_SUPER(TYPE) CLASS_HAS_SUPER_FLAG (TYPE_BINFO (TYPE)) + +/* Return the supertype of class TYPE, or NULL_TREE is it has none. */ +#define CLASSTYPE_SUPER(TYPE) (CLASS_HAS_SUPER (TYPE) ? \ + BINFO_TYPE (TREE_VEC_ELT (TYPE_BINFO_BASETYPES (TYPE), 0)) : NULL_TREE) + +/* True if the class we are compiling is a .java source file; + false if it is a .class bytecode file. */ +extern int compiling_from_source; + +/* The class defined by the actual (main) file we are compiling. */ +extern tree main_class; + +/* The class we are currently processing. */ +extern tree current_class; + +/* Nonzero if we want to automatically do array bounds checking; + on by default. Use -fno-bounds-check to disable. */ + +extern int flag_bounds_check; + +/* Nonzero if we should make is_compiled_class always return 1 for + appropriate classes that we're referencing. */ + +extern int flag_assume_compiled; + +extern int flag_emit_class_files; + +/* The Java .class file that provides main_class; the main input file. */ +extern struct JCF main_jcf[1], *current_jcf; + +typedef struct CPool constant_pool; + +#define CONSTANT_ResolvedFlag 16 + +/* The cpool->data[i] for a ResolvedString points to a STRING_CST. */ +#define CONSTANT_ResolvedString (CONSTANT_String+CONSTANT_ResolvedFlag) + +/* The cpool->data[i] for a ResolvedClass points to a RECORD_TYPE. */ +#define CONSTANT_ResolvedClass (CONSTANT_Class+CONSTANT_ResolvedFlag) + +#define CPOOL_UTF(CPOOL, INDEX) ((tree) (CPOOL)->data[INDEX]) + +/* A NameAndType constant is represented as a TREE_LIST. + The type is the signature string (as an IDENTIFIER_NODE). */ + +#define NAME_AND_TYPE_NAME(CPOOL, IDX) \ + CPOOL_UTF(CPOOL, CPOOL_USHORT1(CPOOL, IDX)) +#define NAME_AND_TYPE_SIGNATURE(CPOOL, IDX) \ + CPOOL_UTF(CPOOL, CPOOL_USHORT2(CPOOL, IDX)) + +/* A FieldRef, MethodRef or InterfaceMethodRef constant + is represented as a TREE_LIST. */ + +#define COMPONENT_REF_CLASS_INDEX(CPOOL, IDX) CPOOL_USHORT1(CPOOL, IDX) +#define COMPONENT_REF_NAME_AND_TYPE(CPOOL, IDX) CPOOL_USHORT2(CPOOL, IDX) +#define COMPONENT_REF_NAME(CPOOL, IDX) \ + NAME_AND_TYPE_NAME (CPOOL, COMPONENT_REF_NAME_AND_TYPE(CPOOL, IDX)) +#define COMPONENT_REF_SIGNATURE(CPOOL, IDX) \ + NAME_AND_TYPE_SIGNATURE (CPOOL, COMPONENT_REF_NAME_AND_TYPE(CPOOL, IDX)) + +/* "Promoted types" that are used for primitive types smaller + than int. We could use int_type_node, but then we would lose + type information (such as needed for debugging). */ +extern tree promoted_byte_type_node; +extern tree promoted_short_type_node; +extern tree promoted_char_type_node; +extern tree promoted_boolean_type_node; + +extern tree byte_type_node; +extern tree short_type_node; +extern tree int_type_node; +extern tree long_type_node; + +extern tree unsigned_byte_type_node; +extern tree unsigned_short_type_node; +extern tree unsigned_int_type_node; +extern tree unsigned_long_type_node; + +extern tree boolean_type_node; +extern tree char_type_node; +extern tree float_type_node; +extern tree double_type_node; + +extern tree object_type_node; +extern tree object_ptr_type_node; +extern tree string_type_node; +extern tree throwable_type_node; + +extern tree byte_array_type_node; +extern tree short_array_type_node; +extern tree int_array_type_node; +extern tree long_array_type_node; +extern tree boolean_array_type_node; +extern tree char_array_type_node; +extern tree double_array_type_node; +extern tree float_array_type_node; +extern tree array_array_type_node; +extern tree object_array_type_node; +extern tree string_array_type_node; +extern tree TYPE_identifier_node; /* "TYPE" */ +extern tree init_identifier_node; /* "" */ +extern tree clinit_identifier_node; /* "" */ +extern tree void_signature_node; /* "()V" */ +extern tree finalize_identifier_node; /* "finalize" */ +extern tree length_identifier_node; /* "length" */ +extern tree this_identifier_node; /* "this" */ +extern tree super_identifier_node; /* "super" */ +extern tree one_elt_array_domain_type; +extern tree void_type_node; +extern tree ptr_type_node; +/* The type of the return address of a subroutine. */ +extern tree return_address_type_node; + +/* Nodes for boolean constants TRUE and FALSE. */ +extern tree boolean_true_node, boolean_false_node; + +/* Integer constants not declared in tree.h. */ +extern tree integer_negative_one_node; +extern tree integer_two_node; +extern tree integer_four_node; + +/* The type for struct methodtable. */ +extern tree methodtable_type; +extern tree methodtable_ptr_type; + +extern tree utf8const_type; +extern tree utf8const_ptr_type; + +extern tree class_type_node; +extern tree class_ptr_type; +extern tree field_type_node; +extern tree constants_type_node; +extern tree dtable_type, dtable_ptr_type; +extern tree field_ptr_type_node; +extern tree field_info_union_node; +extern tree method_type_node; +extern tree method_ptr_type_node; +#define nativecode_ptr_type_node ptr_type_node + +/* References to internal libjava functions we use. */ +extern tree alloc_object_node; +extern tree soft_instanceof_node; +extern tree soft_checkcast_node; +extern tree soft_initclass_node; +extern tree soft_newarray_node; +extern tree soft_anewarray_node; +extern tree soft_multianewarray_node; +extern tree soft_badarrayindex_node; +extern tree throw_node; +extern tree soft_checkarraystore_node; +extern tree soft_monitorenter_node; +extern tree soft_monitorexit_node; +extern tree soft_lookupinterfacemethod_node; +extern tree soft_fmod_node; + +extern tree access_flags_type_node; + +extern tree class_dtable_decl; + +/* They need to be reset before processing each class */ +extern struct CPool *outgoing_cpool; +extern tree current_constant_pool_data_ref; + + +struct lang_identifier +{ + struct tree_identifier ignore; + tree global_value, local_value; + + /* If non-NULL: An ADDR_REF to a VAR_DECL that contains + * the Utf8Const representation of the identifier. */ + tree utf8_ref; +}; + +/* Macros for access to language-specific slots in an identifier. */ +/* UNless specifide, each of these slots contains a DECL node or null. */ + +/* This represents the value which the identifier has in the + file-scope namespace. */ +#define IDENTIFIER_GLOBAL_VALUE(NODE) \ + (((struct lang_identifier *)(NODE))->global_value) +/* This represents the value which the identifier has in the current + scope. */ +#define IDENTIFIER_LOCAL_VALUE(NODE) \ + (((struct lang_identifier *)(NODE))->local_value) + +/* Given an identifier NODE, get the corresponding (non-handle) class. + For get_identifier ("java.lang.Number"), the result is + the struct whose DECL_ASSEMBLER_NAME is "Classjava_lang_Number". */ +#define IDENTIFIER_CLASS_VALUE(NODE) IDENTIFIER_GLOBAL_VALUE(NODE) + +/* Given an identifier NODE, get the corresponding handle class. + For get_identifier ("java.lang.Number"), the result is + the struct whose DECL_ASSEMBLER_NAME is "Hjava_lang_Number". */ +#define IDENTIFIER_HANDLECLASS_VALUE(NODE) ??? + +/* Given a signature of a reference (or array) type, or a method, return the + corresponding type (if one has been allocated). + Do not use for primitive types, since they may be ambiguous. + (E.g. is "I" a signature or a class name?) */ +#define IDENTIFIER_SIGNATURE_TYPE(NODE) IDENTIFIER_GLOBAL_VALUE(NODE) + +/* If non-NULL: An ADDR_REF to a VAR_DECL that contains + the Utf8Const representation of the identifier. */ +#define IDENTIFIER_UTF8_REF(NODE) \ + (((struct lang_identifier *)(NODE))->utf8_ref) + +#define IDENTIFIER_UTF8_DECL(NODE) \ + TREE_OPERAND((((struct lang_identifier *)(NODE))->utf8_ref), 0) + +/* For a FUNCTION_DECL, if we are compiling a .class file, then this is + the position in the .class file of the method code. + Specifically, this is the code itself, not the code attribute. */ +#define DECL_CODE_OFFSET(DECL) (DECL_LANG_SPECIFIC(DECL)->code_offset) +/* Similarly, the length of the bytecode. */ +#define DECL_CODE_LENGTH(DECL) (DECL_LANG_SPECIFIC(DECL)->code_length) +/* Similarly, the position of the LineNumberTable attribute. */ +#define DECL_LINENUMBERS_OFFSET(DECL) \ + (DECL_LANG_SPECIFIC(DECL)->linenumbers_offset) +/* Similarly, the position of the LocalVariableTable attribute + (following the standard attribute header). */ +#define DECL_LOCALVARIABLES_OFFSET(DECL) \ + (DECL_LANG_SPECIFIC(DECL)->localvariables_offset) + +#define DECL_MAX_LOCALS(DECL) (DECL_LANG_SPECIFIC(DECL)->max_locals) +#define DECL_MAX_STACK(DECL) (DECL_LANG_SPECIFIC(DECL)->max_stack) +/* Number of local variable slots needed for the arguments of this function. */ +#define DECL_ARG_SLOT_COUNT(DECL) (DECL_LANG_SPECIFIC(DECL)->arg_slot_count) +/* Pointer to the function's COMPOUND_EXPR tree */ +#define DECL_FUNCTION_BODY(DECL) (DECL_LANG_SPECIFIC(DECL)->function_decl_body) + +/* In a LABEL_DECL, a TREE_VEC that saves the type_map at that point. */ +#define LABEL_TYPE_STATE(NODE) (DECL_INITIAL (NODE)) + +/* In the label of a subroutine, a dummy label that records the + state following a merge of all the ret instructions in this subroutine. */ +#define LABEL_RETURN_LABEL(DECL) DECL_ARGUMENTS(DECL) + +/* In the label of a sub-routine, records the type state at return. + * A local may be TYPE_UNUSED, which means that the local is not + * used (stored to or loaded from) in this subroutine - at least for + * code that we have verified so far. */ +#define LABEL_RETURN_TYPE_STATE(NODE) LABEL_TYPE_STATE (LABEL_RETURN_LABEL (NODE)) + +/* In a TREE_VEC for a LABEL_RETURN_TYPE_STATE, notes that + TREE_VEC_LENGTH has been adjust to the correct stack size. */ +#define RETURN_MAP_ADJUSTED(NODE) TREE_LANG_FLAG_2(NODE) + +/* In the label of a sub-routine, a chain of the return location labels. */ +#define LABEL_RETURN_LABELS(node) DECL_RESULT (LABEL_RETURN_LABEL(node)) + +/* In a LABEL_DECL, the next pending label. + See pending_blocks in expr.c. */ +#define LABEL_PENDING_CHAIN(NODE) DECL_RESULT(NODE) + +/* In a LABEL_DECL, the corresponding bytecode program counter. */ +#define LABEL_PC(NODE) ((NODE)->decl.saved_insns.i) + +/* Used during verification to mark the label has "changed". (See JVM Spec). */ +#define LABEL_CHANGED(NODE) DECL_LANG_FLAG_6(NODE) + +/* In a LABEL_DECL, true if we have verified instructions starting here. */ +#define LABEL_VERIFIED(NODE) (instruction_bits[LABEL_PC(NODE)]&BCODE_VERIFIED) + +/* True if this code is within a subroutine (target of a jsr). */ +#define LABEL_IN_SUBR(NODE) DECL_LANG_FLAG_4(NODE) +/* True if this code is the start of a subroutine (target of a jsr). */ +#define LABEL_IS_SUBR_START(NODE) DECL_LANG_FLAG_5(NODE) + +/* In a LABEL_DECL, if LABEL_IN_SUBR(NODE), points to start of subroutine. */ +#define LABEL_SUBR_START(NODE) DECL_ABSTRACT_ORIGIN(NODE) + +/* In a LABEL_DECL that has LABEL_IS_SUBR_START, this points to the start + of surrounding subroutine in the case of a nested subroutine, + and NULL_TREE otherwise. */ +#define LABEL_SUBR_CONTEXT(NODE) DECL_CONTEXT (LABEL_RETURN_LABEL (NODE)) + +/* The slot number for this local variable. */ +#define DECL_LOCAL_SLOT_NUMBER(NODE) \ + (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->slot_number) +/* The start (bytecode) pc for the valid range of this local variable. */ +#define DECL_LOCAL_START_PC(NODE) \ + (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->start_pc) +/* The end (bytecode) pc for the valid range of this local variable. */ +#define DECL_LOCAL_END_PC(NODE) \ + (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->end_pc) +/* For a VAR_DECLor PARM_DECL, used to chain decls with the same + slot_number in decl_map. */ +#define DECL_LOCAL_SLOT_CHAIN(NODE) \ + (((struct lang_decl_var*)DECL_LANG_SPECIFIC(NODE))->slot_chain) + +/* DECL_LANG_SPECIFIC for FUNCTION_DECLs. */ +struct lang_decl +{ + /* tree chain; not yet used. */ + long code_offset; + int code_length; + long linenumbers_offset; + long localvariables_offset; + int arg_slots; + int max_locals, max_stack, arg_slot_count; + tree function_decl_body; /* Hold all function's statements */ +}; + +/* DECL_LANG_SPECIFIC for VAR_DECL and PARM_DECL. */ +struct lang_decl_var +{ + int slot_number; + int start_pc; + int end_pc; + tree slot_chain; +}; + +struct lang_type +{ + tree signature; + struct JCF *jcf; +}; + +#ifdef JAVA_USE_HANDLES +/* TYPE_BINFO_HANDLE points from a handle-class to its corresponding + non-handle-class, and vice verse. */ + +#define BINFO_HANDLE(NODE) TREE_VEC_ELT ((NODE), 6) + +/* Given a RECORD_TYPE for a handle type, return the corresponding class. */ +#define HANDLE_TO_CLASS_TYPE(HTYPE) BINFO_HANDLE (TYPE_BINFO (HTYPE)) + +/* Given a RECORD_TYPE for a class, return the corresponding handle type. */ +#define CLASS_TO_HANDLE_TYPE(TYPE) BINFO_HANDLE (TYPE_BINFO (TYPE)) +#else +#define HANDLE_TO_CLASS_TYPE(HTYPE) (HTYPE) +#define CLASS_TO_HANDLE_TYPE(TYPE) (TYPE) +#endif + +#define JCF_u4 unsigned long +#define JCF_u2 unsigned short + +extern tree lookup_class PROTO ((tree)); +extern tree lookup_java_constructor PROTO ((tree, tree)); +extern tree lookup_java_method PROTO ((tree, tree, tree)); +extern tree lookup_argument_method PROTO ((tree, tree, tree)); +extern tree promote_type PROTO ((tree)); +extern tree get_constant PROTO ((struct JCF*, int)); +extern tree get_name_constant PROTO ((struct JCF*, int)); +extern tree get_class_constant PROTO ((struct JCF*, int)); +extern tree parse_signature PROTO ((struct JCF *jcf, int sig_index)); +extern int jcf_parse PROTO ((struct JCF*)); +extern tree add_field PROTO ((tree, tree, tree, int)); +extern tree add_method PROTO ((tree, int, tree, tree)); +extern tree add_method_1 PROTO ((tree, int, tree, tree)); +extern tree make_class (); +extern tree push_class PROTO ((tree, tree)); +extern tree unmangle_classname PROTO ((const char *name, int name_length)); +extern tree parse_signature_string PROTO ((const unsigned char *, int)); +extern tree get_type_from_signature PROTO ((tree)); +extern void layout_class PROTO ((tree)); +extern tree make_class (); +extern tree build_class_ref PROTO ((tree)); +extern tree build_dtable_decl PROTO ((tree)); +extern tree build_internal_class_name PROTO ((tree)); +extern tree build_constants_constructor (); +extern tree build_ref_from_constant_pool PROTO ((int)); +extern tree build_utf8_ref PROTO ((tree)); +extern tree ident_subst PROTO ((const char*, int, + const char*, int, int, const char*)); +extern tree identifier_subst PROTO ((const tree, + const char *, int, int, const char *)); +extern tree build_java_signature PROTO ((tree)); +extern tree build_java_argument_signature PROTO ((tree)); +extern void set_java_signature PROTO ((tree, tree)); +extern tree build_static_field_ref PROTO ((tree)); +extern tree build_address_of PROTO ((tree)); +extern tree find_local_variable PROTO ((int index, tree type, int pc)); +extern tree find_stack_slot PROTO ((int index, tree type)); +extern tree build_prim_array_type PROTO ((tree, HOST_WIDE_INT)); +extern tree build_java_array_type PROTO ((tree, HOST_WIDE_INT)); +extern int is_compiled_class PROTO ((tree)); +extern tree mangled_classname PROTO ((char*, tree)); +extern tree lookup_label PROTO ((int)); +extern tree pop_type PROTO ((tree)); +extern void pop_argument_types PROTO ((tree)); +extern tree decode_newarray_type PROTO ((int)); +extern tree lookup_field PROTO ((tree*, tree)); +extern int is_array_type_p PROTO ((tree)); +extern HOST_WIDE_INT java_array_type_length PROTO ((tree)); +extern void load_class PROTO ((tree, int)); + +extern tree lookup_name PROTO ((tree)); +extern tree build_known_method_ref PROTO ((tree, tree, tree, tree, tree)); +extern tree build_class_init PROTO ((tree, tree)); +extern tree build_invokevirtual PROTO ((tree, tree)); +extern tree invoke_build_dtable PROTO ((int, tree)); +extern tree match_java_method PROTO ((tree, tree, tree)); +extern tree build_field_ref PROTO ((tree, tree, tree)); +extern void pushdecl_force_head PROTO ((tree)); +extern tree build_java_binop PROTO ((enum tree_code, tree, tree, tree)); +extern tree binary_numeric_promotion PROTO ((tree, tree, tree *, tree *)); +extern tree build_decl_no_layout PROTO ((enum tree_code, tree, tree)); +extern tree build_java_arrayaccess PROTO ((tree, tree, tree)); +extern tree build_newarray PROTO ((int, tree)); +extern tree build_anewarray PROTO ((tree, tree)); +extern tree build_java_array_length_access PROTO ((tree)); +extern tree build_java_arraynull_check PROTO ((tree, tree, tree)); +extern tree create_label_decl PROTO ((tree)); +extern void push_labeled_block PROTO ((tree)); + +/* Access flags etc for a method (a FUNCTION_DECL): */ + +#define METHOD_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL) +#define METHOD_PRIVATE(DECL) TREE_PRIVATE (DECL) +#define METHOD_PROTECTED(DECL) TREE_PROTECTED (DECL) +#define METHOD_STATIC(DECL) DECL_LANG_FLAG_2 (DECL) +#define METHOD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL) +#define METHOD_SYNCHRONIZED(DECL) DECL_LANG_FLAG_4 (DECL) +#define METHOD_NATIVE(DECL) DECL_EXTERNAL(DECL) +#define METHOD_ABSTRACT(DECL) DECL_LANG_FLAG_5 (DECL) +#define METHOD_TRANSIENT(DECL) DECL_LANG_FLAG_6 (DECL) + +#define DECL_CONSTRUCTOR_P(DECL) DECL_LANG_FLAG_7(DECL) + +/* Access flags etc for a variable/field (a FIELD_DECL): */ + +#define FIELD_PRIVATE(DECL) TREE_PRIVATE (DECL) +#define FIELD_PROTECTED(DECL) TREE_PROTECTED (DECL) +#define FIELD_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL) +#define FIELD_STATIC(DECL) TREE_STATIC (DECL) +#define FIELD_FINAL(DECL) DECL_LANG_FLAG_3 (DECL) +#define FIELD_VOLATILE(DECL) DECL_LANG_FLAG_4 (DECL) +#define FIELD_TRANSIENT(DECL) DECL_LANG_FLAG_5 (DECL) + +/* Initialized flag on variable/field/parm decl */ + +#define INITIALIZED_P(DECL) DECL_LANG_FLAG_6 (DECL) + +/* Access flags etc for a class (a TYPE_DECL): */ + +#define CLASS_PUBLIC(DECL) DECL_LANG_FLAG_1 (DECL) +#define CLASS_FINAL(DECL) DECL_LANG_FLAG_3 (DECL) +#define CLASS_INTERFACE(DECL) DECL_LANG_FLAG_4 (DECL) +#define CLASS_ABSTRACT(DECL) DECL_LANG_FLAG_5 (DECL) +#define CLASS_SUPER(DECL) DECL_LANG_FLAG_6 (DECL) + +/* The number of virtual methods in this class's dispatch table. + Does not include initial two dummy entries (one points to the + Class object, and the other is for G++ -fvtable-thunks compatibility). */ +#define TYPE_NVIRTUALS(TYPE) TYPE_BINFO_VIRTUALS (TYPE) + +/* A TREE_VEC (indexed by DECL_VINDEX) containing this class's + virtual methods. */ +#define TYPE_VTABLE(TYPE) TYPE_BINFO_VTABLE(TYPE) + +/* True of a RECORD_TYPE of a class/interface type (not array type) */ +#define CLASS_P(TYPE) TYPE_LANG_FLAG_4 (TYPE) +/* Use CLASS_LOADED_P? FIXME */ +#define CLASS_COMPLETE_P(DECL) DECL_LANG_FLAG_2 (DECL) + +/* This maps a bytecode offset (PC) to various flags, + listed below (starting with BCODE_). */ +extern char *instruction_bits; + +/* True iff the byte is the start of an instruction. */ +#define BCODE_INSTRUCTION_START 1 + +/* True iff there is a jump to this location. */ +#define BCODE_JUMP_TARGET 2 + +/* True iff there is a return to this location. + (I.e. the preceedng instruction was a call.) */ +#define BCODE_RETURN_TARGET 4 + +/* True iff this is the start of an exception handler. */ +#define BCODE_EXCEPTION_TARGET 16 + +/* True iff there is a jump to this location (and it needs a label). */ +#define BCODE_TARGET \ + (BCODE_JUMP_TARGET|BCODE_RETURN_TARGET \ + | BCODE_EXCEPTION_TARGET) + +/* True iff there is an entry in the linenumber table for this location. */ +#define BCODE_HAS_LINENUMBER 32 + +/* True iff there is more than one entry in the linenumber table for + this location. (This probably does not make much sense.) */ +#define BCODE_HAS_MULTI_LINENUMBERS 64 + +/* True if this instruction has been verified. */ +#define BCODE_VERIFIED 8 + +/* A pointer to the line number table of the current method. */ +extern unsigned char *linenumber_table; +/* The length (in items) of the line number table. */ +extern int linenumber_count; + +/* In type_map, means that slot is uninitialized or otherwise unusable. */ +#define TYPE_UNKNOWN NULL_TREE + +/* In type_map, means the second half of a 64-bit double or long. */ +#define TYPE_SECOND void_type_node + +/* In type_map, means the null type (i.e. type of a null reference). */ +#define TYPE_NULL ptr_type_node + +/* In a type map means the type the address subroutine return address. */ +#define TYPE_RETURN_ADDR return_address_type_node + +/* In a subroutine's return type map, indicates that the slot was neither + used nor set in the subroutine. */ +#define TYPE_UNUSED error_mark_node + +/* A array mapping variable/stack slot index to the type current + in that variable/stack slot. + TYPE_UNKNOWN, TYPE_SECOND, and TYPE_NULL are special cases. */ +extern tree *type_map; + +/* Map a stack index to the type currently in that slot. */ +#define stack_type_map (type_map+DECL_MAX_LOCALS(current_function_decl)) + +/* True iff TYPE takes two variable/stack slots. */ +#define TYPE_IS_WIDE(TYPE) \ + ((TYPE) == double_type_node || (TYPE) == long_type_node) + +/* True iff TYPE is a Java array type. */ +#define TYPE_ARRAY_P(TYPE) TYPE_LANG_FLAG_1 (TYPE) + +/* If FUNCTION_TYPE or METHOD_TYPE: cache for build_java_argument_signature. */ +#define TYPE_ARGUMENT_SIGNATURE(TYPE) TYPE_VFIELD(TYPE) + +/* Given an array type, give the type of the elements. */ +/* FIXME this use of TREE_TYPE conflicts with something or other. */ +#define TYPE_ARRAY_ELEMENT(ATYPE) TREE_TYPE(ATYPE) + +/* True if class TYPE has been loaded. */ +#define CLASS_LOADED_P(TYPE) TYPE_LANG_FLAG_2 (TYPE) + +/* True if class TYPE was defined in Java source code. */ +#define CLASS_FROM_SOURCE_P(TYPE) TYPE_LANG_FLAG_3 (TYPE) + +/* True if identifier ID was seen while processing a single type import stmt */ +#define IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P(ID) TREE_LANG_FLAG_0 (ID) + +/* True if identifier ID was seen while processing an import statement */ +#define IS_A_CLASSFILE_NAME(ID) TREE_LANG_FLAG_1 (ID) + +/* True if ID is a qualified named (contains . or /) */ +#define QUALIFIED_P(ID) TREE_LANG_FLAG_2 (ID) + +/* True if ID is an already processed import on demand */ +#define IS_AN_IMPORT_ON_DEMAND_P(ID) TREE_LANG_FLAG_3 (ID) + +/* True if EXPR is RHS sub-tree of a compound assign expression */ +#define COMPOUND_ASSIGN_P(EXPR) TREE_LANG_FLAG_1 (EXPR) + +/* True if EXPR (a WFL in that case) was created after the + reduction of PRIMARY . XXX */ +#define PRIMARY_P(EXPR) TREE_LANG_FLAG_2 (EXPR) + +/* True if EXPR (a MODIFY_EXPR in that case) is the result of variable + initialization during its declaration */ +#define MODIFY_EXPR_FROM_INITIALIZATION_P(EXPR) TREE_LANG_FLAG_2 (EXPR) + +/* True if EXPR (a WFL in that case) resolves into an expression name */ +#define RESOLVE_EXPRESSION_NAME_P(WFL) TREE_LANG_FLAG_0 (WFL) + +/* True if EXPR (a LOOP_EXPR in that case) is part of a for statement */ +#define IS_FOR_LOOP_P(EXPR) TREE_LANG_FLAG_0 (EXPR) + +/* True if EXPR (a WFL in that case) resolves into a package name */ +#define RESOLVE_PACKAGE_NAME_P(WFL) TREE_LANG_FLAG_3 (WFL) + +/* True if EXPR (a WFL in that case) resolves into a type name */ +#define RESOLVE_TYPE_NAME_P(WFL) TREE_LANG_FLAG_4 (WFL) + +/* True if STMT (a WFL in that case) holds a BREAK statement */ +#define IS_BREAK_STMT_P(WFL) TREE_LANG_FLAG_5 (WFL) + +/* Add a FIELD_DECL to RECORD_TYPE RTYPE. + The field has name NAME (a char*), and type FTYPE. + Unless this is the first field, FIELD most hold the previous field. + FIELD is set to the newly created FIELD_DECL. + + We set DECL_ARTIFICIAL so these fields get skipped by make_class_data + if compiling java.lang.Object or java.lang.Class. */ + +#define PUSH_FIELD(RTYPE, FIELD, NAME, FTYPE) \ +{ tree tmp_field = build_decl (FIELD_DECL, get_identifier(NAME), FTYPE); \ + if (TYPE_FIELDS (RTYPE) == NULL_TREE) TYPE_FIELDS (RTYPE) = tmp_field; \ + else TREE_CHAIN(FIELD) = tmp_field; \ + DECL_CONTEXT (tmp_field) = RTYPE; \ + DECL_ARTIFICIAL (tmp_field) = 1; \ + FIELD = tmp_field; } + +#define FINISH_RECORD(RTYPE) layout_type (RTYPE) + +/* Start building a RECORD_TYPE constructor with a given TYPE in CONS. */ +#define START_RECORD_CONSTRUCTOR(CONS, CTYPE) { \ + CONS = build (CONSTRUCTOR, CTYPE, NULL_TREE, NULL_TREE);\ + TREE_CHAIN(CONS) = TYPE_FIELDS (CTYPE); } + +/* Append a field initializer to CONS for the dummy field for the inherited + fields. The dummy field has the given VALUE, and the same type as the + super-class. Must be specified before calls to PUSH_FIELD_VALUE. */ + +#define PUSH_SUPER_VALUE(CONS, VALUE) {\ + tree field = TREE_CHAIN(CONS);\ + if (DECL_NAME (field) != NULL_TREE) abort();\ + CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));\ + TREE_CHAIN(CONS) = TREE_CHAIN (field); } + +/* Append a field initializer to CONS for a field with the given VALUE. + NAME is a char* string used for error checking; + the initializer must be specified in order. */ +#define PUSH_FIELD_VALUE(CONS, NAME, VALUE) {\ + tree field = TREE_CHAIN(CONS);\ + if (strcmp (IDENTIFIER_POINTER (DECL_NAME (field)), NAME) != 0) abort();\ + CONSTRUCTOR_ELTS(CONS) = tree_cons (field, VALUE, CONSTRUCTOR_ELTS(CONS));\ + TREE_CHAIN(CONS) = TREE_CHAIN (field); } + +/* Finish creating a record CONSTRUCTOR CONS. */ +#define FINISH_RECORD_CONSTRUCTOR(CONS) \ + CONSTRUCTOR_ELTS(CONS) = nreverse (CONSTRUCTOR_ELTS(CONS)) + +/* New tree code for expression, so we can expand then individually. */ +#define JAVA_UNARY_PLUS_EXPR ((int)LAST_AND_UNUSED_TREE_CODE + 2) +#define JAVA_NEW_ARRAY_EXPR ((int)LAST_AND_UNUSED_TREE_CODE + 3) +#define JAVA_NEW_CLASS_EXPR ((int)LAST_AND_UNUSED_TREE_CODE + 4) +#define JAVA_THIS_EXPR ((int)LAST_AND_UNUSED_TREE_CODE + 5) + +/* Macro(s) using the definitions above */ +#define CALL_CONSTRUCTOR_P(NODE) (TREE_CODE (NODE) == JAVA_NEW_CLASS_EXPR) + diff --git a/gcc/java/javaop.def b/gcc/java/javaop.def new file mode 100644 index 00000000000..a722a8b69f9 --- /dev/null +++ b/gcc/java/javaop.def @@ -0,0 +1,314 @@ +/* Table of opcodes for byte codes defined by the Java(TM) virtual + machine specification. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. + +Written by Per Bothner , February 1996. +*/ + +/* JAVAOP (OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE), where: + OPNAME is the name of the opcode. + OPCODE is the 1-byte opcode value. + OPKIND is the kind of operation. + OPERAND_TYPE is the type operands affected. + OPERAND_VALUE tells where to get the value. (Its meaning + depends on OPKIND.) */ + +/* Various macro used in OPERAND_VALUE: +IMMEDIATE_s1: An immediate signed 1-byte value in the byte-code stream. +IMMEDIATE_s2: An immediate signed 2-byte value in the byte-code stream. +IMMEDIATE_u1: An immediate unsigned 1-byte value in the byte-code stream. +IMMEDIATE_u2: An immediate unsigned 2-byte value in the byte-code stream. + +CONST_INDEX_1: An immediate unsigned 1-byte index into the constant pool. +CONST_INDEX_2: An immediate unsigned 2-byte index into the constant pool. +*/ + +/* More specifically, this is the meaning of the various OPKINDs: + +BINOP: binary operation + OPERAND_TYPE is the argument type. + OPERAND_VALUE is PLUS, MINUS, MULT, TRUNC_DIV, RDIV, REM, + LSHIFT, RSHIFT, URSHIFT, BIT_AND, BIT_IOR, BIT_XOR, + COMPARE, COMPARE_L, or COMPARE_G. + +UNOP: unary operation + OPERAND_TYPE is the argument type. + OPERAND_VALUE is NEG. + +INVOKE: invoke operations + OPERAND_TYPE is VIRTUAL, SPECIAL, STATIC, or INTERFACE. + OPERAND_VALUE is 1 if interface, 0 otherwise. + +OBJECT: new, checkcast, instanceof + OPERAND_TYPE is PTR. + OPERAND_VALUE is NEW, CHECKCAST, or INSTANCEOF. + +BRANCH: branch operations + OPERAND_TYPE is GOTO, CALL, or RETURN. + OPERAND_VALUE is IMMEDIATE_s2, VAR_INDEX_1, IMMEDIATE_s4, + or VAR_INDEX_2. + +STACK: Various stack operations. + +PUSHC: Push a constant onto the operand stack. + OPERAND_VALUE maybe be the value to push, + or IMMEDIATE_s1 or IMMEDIATE_s2 if the constant is immediate, + or CONST_INDEX_1 or CONST_INDEX_2 for a constant pool index. + +LOAD: Push a value from a local variable onto the operand stack. + OPERAND_VALUE is the index of the local variable in the current + Java frame. It can be a literal, or IMMEDIATE_i2. + +CONVERT: Convert top of stack value from one type to another. + OPERAND_TYPE is the argument type. + OPERAND_VALUE is the result type. + +TEST: Compares an integer (popped from the stack) against zero. + If the test (in OPERAND_VALUE) is true, goto a relative + offset given by the next two bytes. + +COND: Compares two values (popped from the stack) againt each other. + If the test (in OPERAND_VALUE) is true, goto a relative + offset given by the next two bytes. + +SWITCH: + OPERAND_VALUE is either TABLE or LOOKUP. + +ARRAY: + OPERAND_VALUE is LOAD, STORE, LENGTH, or NEW. + +FIELD: Extracts from or stores into a field. + OPERAND_TYPE is 1 for a static field, 0 for a regular field. + OPERAND_VALUE is 1 for a put operation, 0 for a get operation. + +SPECIAL: + Random bunch of opcodes. + +*/ + +JAVAOP (nop, 0, STACK, POP, 0) +JAVAOP (aconst_null, 1, PUSHC, PTR, 0) +JAVAOP (iconst_m1, 2, PUSHC, INT, -1) +JAVAOP (iconst_0, 3, PUSHC, INT, 0) +JAVAOP (iconst_1, 4, PUSHC, INT, 1) +JAVAOP (iconst_2, 5, PUSHC, INT, 2) +JAVAOP (iconst_3, 6, PUSHC, INT, 3) +JAVAOP (iconst_4, 7, PUSHC, INT, 4) +JAVAOP (iconst_5, 8, PUSHC, INT, 5) +JAVAOP (lconst_0, 9, PUSHC, LONG, 0) +JAVAOP (lconst_1, 10, PUSHC, LONG, 1) +JAVAOP (fconst_0, 11, PUSHC, FLOAT, 0) +JAVAOP (fconst_1, 12, PUSHC, FLOAT, 1) +JAVAOP (fconst_2, 13, PUSHC, FLOAT, 2) +JAVAOP (dconst_0, 14, PUSHC, DOUBLE, 0) +JAVAOP (dconst_1, 15, PUSHC, DOUBLE, 1) +JAVAOP (bipush, 16, PUSHC, INT, IMMEDIATE_s1) +JAVAOP (sipush, 17, PUSHC, INT, IMMEDIATE_s2) +JAVAOP (ldc, 18, PUSHC, INT, CONST_INDEX_1) +JAVAOP (ldc_w, 19, PUSHC, INT, CONST_INDEX_2) +JAVAOP (ldc2_w, 20, PUSHC, LONG, CONST_INDEX_2) +JAVAOP (iload, 21, LOAD, INT, IMMEDIATE_u1) +JAVAOP (lload, 22, LOAD, LONG, IMMEDIATE_u1) +JAVAOP (fload, 23, LOAD, FLOAT, IMMEDIATE_u1) +JAVAOP (dload, 24, LOAD, DOUBLE, IMMEDIATE_u1) +JAVAOP (aload, 25, LOAD, PTR, IMMEDIATE_u1) +JAVAOP (iload_0, 26, LOAD, INT, 0) +JAVAOP (iload_1, 27, LOAD, INT, 1) +JAVAOP (iload_2, 28, LOAD, INT, 2) +JAVAOP (iload_3, 29, LOAD, INT, 3) +JAVAOP (lload_0, 30, LOAD, LONG, 0) +JAVAOP (lload_1, 31, LOAD, LONG, 1) +JAVAOP (lload_2, 32, LOAD, LONG, 2) +JAVAOP (lload_3, 33, LOAD, LONG, 3) +JAVAOP (fload_0, 34, LOAD, FLOAT, 0) +JAVAOP (fload_1, 35, LOAD, FLOAT, 1) +JAVAOP (fload_2, 36, LOAD, FLOAT, 2) +JAVAOP (fload_3, 37, LOAD, FLOAT, 3) +JAVAOP (dload_0, 38, LOAD, DOUBLE, 0) +JAVAOP (dload_1, 39, LOAD, DOUBLE, 1) +JAVAOP (dload_2, 40, LOAD, DOUBLE, 2) +JAVAOP (dload_3, 41, LOAD, DOUBLE, 3) +JAVAOP (aload_0, 42, LOAD, PTR, 0) +JAVAOP (aload_1, 43, LOAD, PTR, 1) +JAVAOP (aload_2, 44, LOAD, PTR, 2) +JAVAOP (aload_3, 45, LOAD, PTR, 3) +JAVAOP (iaload, 46, ARRAY, INT, LOAD) +JAVAOP (laload, 47, ARRAY, LONG, LOAD) +JAVAOP (faload, 48, ARRAY, FLOAT, LOAD) +JAVAOP (daload, 49, ARRAY, DOUBLE, LOAD) +JAVAOP (aaload, 50, ARRAY, PTR, LOAD) +JAVAOP (baload, 51, ARRAY, BYTE, LOAD) +JAVAOP (caload, 52, ARRAY, CHAR, LOAD) +JAVAOP (saload, 53, ARRAY, SHORT, LOAD) +JAVAOP (istore, 54, STORE, INT, IMMEDIATE_u1) +JAVAOP (lstore, 55, STORE, LONG, IMMEDIATE_u1) +JAVAOP (fstore, 56, STORE, FLOAT, IMMEDIATE_u1) +JAVAOP (dstore, 57, STORE, DOUBLE, IMMEDIATE_u1) +JAVAOP (astore, 58, STORE, PTR, IMMEDIATE_u1) +JAVAOP (istore_0, 59, STORE, INT, 0) +JAVAOP (istore_1, 60, STORE, INT, 1) +JAVAOP (istore_2, 61, STORE, INT, 2) +JAVAOP (istore_3, 62, STORE, INT, 3) +JAVAOP (lstore_0, 63, STORE, LONG, 0) +JAVAOP (lstore_1, 64, STORE, LONG, 1) +JAVAOP (lstore_2, 65, STORE, LONG, 2) +JAVAOP (lstore_3, 66, STORE, LONG, 3) +JAVAOP (fstore_0, 67, STORE, FLOAT, 0) +JAVAOP (fstore_1, 68, STORE, FLOAT, 1) +JAVAOP (fstore_2, 69, STORE, FLOAT, 2) +JAVAOP (fstore_3, 70, STORE, FLOAT, 3) +JAVAOP (dstore_0, 71, STORE, DOUBLE, 0) +JAVAOP (dstore_1, 72, STORE, DOUBLE, 1) +JAVAOP (dstore_2, 73, STORE, DOUBLE, 2) +JAVAOP (dstore_3, 74, STORE, DOUBLE, 3) +JAVAOP (astore_0, 75, STORE, PTR, 0) +JAVAOP (astore_1, 76, STORE, PTR, 1) +JAVAOP (astore_2, 77, STORE, PTR, 2) +JAVAOP (astore_3, 78, STORE, PTR, 3) +JAVAOP (iastore, 79, ARRAY, INT, STORE) +JAVAOP (lastore, 80, ARRAY, LONG, STORE) +JAVAOP (fastore, 81, ARRAY, FLOAT, STORE) +JAVAOP (dastore, 82, ARRAY, DOUBLE, STORE) +JAVAOP (aastore, 83, ARRAY, PTR, STORE) +JAVAOP (bastore, 84, ARRAY, BYTE, STORE) +JAVAOP (castore, 85, ARRAY, CHAR, STORE) +JAVAOP (sastore, 86, ARRAY, SHORT, STORE) +JAVAOP (pop, 87, STACK, POP, 1) +JAVAOP (pop2, 88, STACK, POP, 2) +JAVAOP (dup, 89, STACK, DUP, 1) +JAVAOP (dup_x1, 90, STACK, DUPx1, 1) +JAVAOP (dup_x2, 91, STACK, DUPx2, 1) +JAVAOP (dup2, 92, STACK, DUP, 2) +JAVAOP (dup2_x1, 93, STACK, DUPx1, 2) +JAVAOP (dup2_x2, 94, STACK, DUPx2, 2) +JAVAOP (swap, 95, STACK, SWAP, 0) +JAVAOP (iadd, 96, BINOP, INT, PLUS) +JAVAOP (ladd, 97, BINOP, LONG, PLUS) +JAVAOP (fadd, 98, BINOP, FLOAT, PLUS) +JAVAOP (dadd, 99, BINOP, DOUBLE, PLUS) +JAVAOP (isub, 100, BINOP, INT, MINUS) +JAVAOP (lsub, 101, BINOP, LONG, MINUS) +JAVAOP (fsub, 102, BINOP, FLOAT, MINUS) +JAVAOP (dsub, 103, BINOP, DOUBLE, MINUS) +JAVAOP (imul, 104, BINOP, INT, MULT) +JAVAOP (lmul, 105, BINOP, LONG, MULT) +JAVAOP (fmul, 106, BINOP, FLOAT, MULT) +JAVAOP (dmul, 107, BINOP, DOUBLE, MULT) +JAVAOP (idiv, 108, BINOP, INT, TRUNC_DIV) +JAVAOP (ldiv, 109, BINOP, LONG, TRUNC_DIV) +JAVAOP (fdiv, 110, BINOP, FLOAT, RDIV) +JAVAOP (ddiv, 111, BINOP, DOUBLE, RDIV) +JAVAOP (irem, 112, BINOP, INT, REM) +JAVAOP (lrem, 113, BINOP, LONG, REM) +JAVAOP (frem, 114, BINOP, FLOAT, REM) +JAVAOP (drem, 115, BINOP, DOUBLE, REM) +JAVAOP (ineg, 116, UNOP, INT, NEG) +JAVAOP (lneg, 117, UNOP, LONG, NEG) +JAVAOP (fneg, 118, UNOP, FLOAT, NEG) +JAVAOP (dneg, 119, UNOP, DOUBLE, NEG) +JAVAOP (ishl, 120, BINOP, INT, LSHIFT) +JAVAOP (lshl, 121, BINOP, LONG, LSHIFT) +JAVAOP (ishr, 122, BINOP, INT, RSHIFT) +JAVAOP (lshr, 123, BINOP, LONG, RSHIFT) +JAVAOP (iushr, 124, BINOP, INT, URSHIFT) +JAVAOP (lushr, 125, BINOP, LONG, URSHIFT) +JAVAOP (iand, 126, BINOP, INT, BIT_AND) +JAVAOP (land, 127, BINOP, LONG, BIT_AND) +JAVAOP (ior, 128, BINOP, INT, BIT_IOR) +JAVAOP (lor, 129, BINOP, LONG, BIT_IOR) +JAVAOP (ixor, 130, BINOP, INT, BIT_XOR) +JAVAOP (lxor, 131, BINOP, LONG, BIT_XOR) +JAVAOP (iinc, 132, SPECIAL, INT, IINC) +JAVAOP (i2l, 133, CONVERT, INT, LONG) +JAVAOP (i2f, 134, CONVERT, INT, FLOAT) +JAVAOP (i2d, 135, CONVERT, INT, DOUBLE) +JAVAOP (l2i, 136, CONVERT, LONG, INT) +JAVAOP (l2f, 137, CONVERT, LONG, FLOAT) +JAVAOP (l2d, 138, CONVERT, LONG, DOUBLE) +JAVAOP (f2i, 139, CONVERT, FLOAT, INT) +JAVAOP (f2l, 140, CONVERT, FLOAT, LONG) +JAVAOP (f2d, 141, CONVERT, FLOAT, DOUBLE) +JAVAOP (d2i, 142, CONVERT, DOUBLE, INT) +JAVAOP (d2l, 143, CONVERT, DOUBLE, LONG) +JAVAOP (d2f, 144, CONVERT, DOUBLE, FLOAT) +JAVAOP (i2b, 145, CONVERT2, INT, BYTE) +JAVAOP (i2c, 146, CONVERT2, INT, CHAR) +JAVAOP (i2s, 147, CONVERT2, INT, SHORT) +JAVAOP (lcmp, 148, BINOP, LONG, COMPARE) +JAVAOP (fcmpl, 149, BINOP, FLOAT, COMPARE_L) +JAVAOP (fcmpg, 150, BINOP, FLOAT, COMPARE_G) +JAVAOP (dcmpl, 151, BINOP, DOUBLE, COMPARE_L) +JAVAOP (dcmpg, 152, BINOP, DOUBLE, COMPARE_G) +JAVAOP (ifeq, 153, TEST, INT, EQ) +JAVAOP (ifne, 154, TEST, INT, NE) +JAVAOP (iflt, 155, TEST, INT, LT) +JAVAOP (ifge, 156, TEST, INT, GE) +JAVAOP (ifgt, 157, TEST, INT, GT) +JAVAOP (ifle, 158, TEST, INT, LE) +JAVAOP (if_icmpeq, 159, COND, INT, EQ) +JAVAOP (if_icmpne, 160, COND, INT, NE) +JAVAOP (if_icmplt, 161, COND, INT, LT) +JAVAOP (if_icmpge, 162, COND, INT, GE) +JAVAOP (if_icmpgt, 163, COND, INT, GT) +JAVAOP (if_icmple, 164, COND, INT, LE) +JAVAOP (if_acmpeq, 165, COND, PTR, EQ) +JAVAOP (if_acmpne, 166, COND, PTR, NE) +JAVAOP (goto, 167, BRANCH, GOTO, IMMEDIATE_s2) +JAVAOP (jsr, 168, JSR, CALL, IMMEDIATE_s2) +JAVAOP (ret, 169, RET, RETURN, VAR_INDEX_1) +JAVAOP (tableswitch, 170, SWITCH, INT, TABLE) +JAVAOP (lookupswitch, 171, SWITCH, INT, LOOKUP) +JAVAOP (ireturn, 172, RETURN, INT, 0) +JAVAOP (lreturn, 173, RETURN, LONG, 0) +JAVAOP (freturn, 174, RETURN, FLOAT, 0) +JAVAOP (dreturn, 175, RETURN, DOUBLE, 0) +JAVAOP (areturn, 176, RETURN, PTR, 0) +JAVAOP (return, 177, RETURN, VOID, 0) +JAVAOP (getstatic, 178, FIELD, 1, 0) +JAVAOP (putstatic, 179, FIELD, 1, 1) +JAVAOP (getfield, 180, FIELD, 0, 0) +JAVAOP (putfield, 181, FIELD, 0, 1) +JAVAOP (invokevirtual, 182, INVOKE, VIRTUAL,0) +JAVAOP (invokespecial, 183, INVOKE, SPECIAL, 0) +JAVAOP (invokestatic, 184, INVOKE, STATIC, 0) +JAVAOP (invokeinterface,185, INVOKE, INTERFACE, 1) +JAVAOP (new, 187, OBJECT, PTR, NEW) +JAVAOP (newarray, 188, ARRAY, NUM, NEW) +JAVAOP (anewarray, 189, ARRAY, PTR, NEW) +JAVAOP (arraylength, 190, ARRAY, INT, LENGTH) +JAVAOP (athrow, 191, SPECIAL, ANY, THROW) +JAVAOP (checkcast, 192, OBJECT, PTR, CHECKCAST) +JAVAOP (instanceof, 193, OBJECT, PTR, INSTANCEOF) +JAVAOP (monitorenter, 194, SPECIAL, MONITOR, ENTER) +JAVAOP (monitorexit, 195, SPECIAL, MONITOR, EXIT) +JAVAOP (wide, 196, SPECIAL, ANY, WIDE) +JAVAOP (multianewarray,197, ARRAY, MULTI, NEW) +JAVAOP (ifnull, 198, TEST, PTR, EQ) +JAVAOP (ifnonnull, 199, TEST, PTR, NE) +JAVAOP (goto_w, 200, BRANCH, GOTO, IMMEDIATE_s4) +JAVAOP (jsr_w, 201, JSR, CALL, IMMEDIATE_s4) +JAVAOP (breakpoint, 202, SPECIAL, ANY, BREAK) +JAVAOP (ret_w, 209, RET, RETURN, VAR_INDEX_2) +JAVAOP (impdep1, 254, IMPL, ANY, 1) +JAVAOP (impdep2, 255, IMPL, ANY, 2) diff --git a/gcc/java/javaop.h b/gcc/java/javaop.h new file mode 100644 index 00000000000..f4ae05006be --- /dev/null +++ b/gcc/java/javaop.h @@ -0,0 +1,142 @@ +/* Utility macros to handle Java(TM) byte codes. + + Copyright (C) 1996 Free Software Foundation, Inc. + +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, 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 GNU CC; 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. */ + +/* Written by Per Bothner , February 1996. */ + +#ifndef JAVAOP_H +#define JAVAOP_H + +typedef char int8; +typedef unsigned char uint8; +#ifndef int16 +#define int16 short +#endif +typedef unsigned int16 uint16; + +#ifndef int32 +#define int32 long +#endif +typedef unsigned int32 uint32; + +/* A signed 64-bit (or more) integral type, suiteable for Java's 'long'. */ +#ifndef int64 +#define int64 long long +#endif +/* An unsigned 64-bit (or more) integral type, same length as int64. */ +#ifndef uint64 +#define uint64 unsigned int64 +#endif + +typedef uint16 jchar; +typedef int8 jbyte; +typedef int16 jshort; +typedef int32 jint; +typedef int64 jlong; +typedef void* jref; + +/* A 32-bit IEEE single-precision float. */ +#ifndef jfloat +#define jfloat float +#endif + +/* A 32-bit IEEE double-precision float. */ +#ifndef jdouble +#define jdouble double +#endif + +union Word { + jint i; + jfloat f; + void *p; +}; + +/* A jword is an unsigned integral type big enough for a 32-bit jint + or jfloat *or* a pointer. It is the type appropriate for stack + locations and local variables in a Java interpreter. */ + + +#ifndef jword +#define jword uint32 +#endif + +#if !defined(inline) && !defined(__GC__) && !defined(__cplusplus) +#define inline static +#endif + +#ifndef IMMEDIATE_u1 +#define IMMEDIATE_u1 (PC++, CHECK_PC_IN_RANGE(PC), BCODE[PC-1]) +#endif +#ifndef IMMEDIATE_s1 +#define IMMEDIATE_s1 (PC++, CHECK_PC_IN_RANGE(PC), (signed char)BCODE[PC-1]) +#endif +#ifndef IMMEDIATE_s2 +#define IMMEDIATE_s2 (PC+=2, CHECK_PC_IN_RANGE(PC), \ + (signed char) BCODE[PC-2] * 256 + BCODE[PC-1]) +#endif +#ifndef IMMEDIATE_u2 +#define IMMEDIATE_u2 (PC+=2, CHECK_PC_IN_RANGE(PC),\ + (BCODE[PC-2] * 256 + BCODE[PC-1])) +#endif +#ifndef IMMEDIATE_s4 +#define IMMEDIATE_s4 (PC+=4, CHECK_PC_IN_RANGE(PC), \ + ((jint)((BCODE[PC-4] << 24) | (BCODE[PC-3] << 16) \ + | (BCODE[PC-2] << 8) | (BCODE[PC-1])))) +#endif + +inline jfloat +WORD_TO_FLOAT(jword w) +{ union Word wu; + wu.i = w; + return wu.f; +} + +inline jlong +WORDS_TO_LONG(jword hi, jword lo) +{ + return ((jlong) hi << 32) | ((jlong)lo & (((jlong)1 << 32) -1)); +} + +union DWord { + jdouble d; + jlong l; + jword w[2]; +}; + +inline jdouble +WORDS_TO_DOUBLE(jword hi, jword lo) +{ union DWord wu; + wu.l = WORDS_TO_LONG(hi, lo); + return wu.d; +} + +/* If PREFIX_CHAR is the first character of the Utf8 encoding of a character, + return the number of bytes taken by the encoding. + Return -1 for a continuation character. */ +#define UT8_CHAR_LENGTH(PREFIX_CHAR) \ + ((unsigned char)(PREFIX_CHAR) < 128 ? 1 \ + : ((PREFIX_CHAR) & 0x40) == 0 ? -1 \ + : ((PREFIX_CHAR) & 0x20) == 0 ? 2 \ + : ((PREFIX_CHAR) & 0x10) == 0 ? 3 \ + : ((PREFIX_CHAR) & 0x08) == 0 ? 4 : 5) + +#endif /* !JAVAOP_H */ diff --git a/gcc/java/jcf-dump.c b/gcc/java/jcf-dump.c new file mode 100644 index 00000000000..749aa82146f --- /dev/null +++ b/gcc/java/jcf-dump.c @@ -0,0 +1,1072 @@ +/* Program to dump out a Java(TM) .class file. + Functionally similar to Sun's javap. + + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +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, 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 GNU CC; 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. */ + +/* Written by Per Bothner , February 1996. */ + +/* + jcf-dump is a program to print out the contents of class files. + Usage: jcf-dump [FLAGS] CLASS + Each CLASS is either: + + the name of a class in the CLASSPATH (e.g "java.lang.String"), or + + the name of a class *file* (e.g. "/home/me/work/package/Foo.class"). + + The name of a .zip or .jar file (which prints all the classes in the + archive). + + OPTIONS: + -c + Dis-assemble each method. + -classpath PATH + Overrides $CLASSPATH. + --print-main + Print nothing if there is no valid "main" method; + otherwise, print only the class name. + --javap + Print output in the style of Sun's javap program. VERY UNFINISHED. + */ + + +#include +#include "jcf.h" + +/* Outout file. */ +FILE *out; +/* Name of output file, if NULL if stdout. */ +char *output_file = NULL; + +int verbose = 0; + +int flag_disassemble_methods = 0; +int flag_print_class_info = 1; +int flag_print_constant_pool = 1; +int flag_print_fields = 1; +int flag_print_methods = 1; +int flag_print_attributes = 1; + +/* Print names of classes that have a "main" method. */ +int flag_print_main = 0; + +/* Index in constant pool of this class. */ +int this_class_index = 0; + +int class_access_flags = 0; + +/* Print in format similar to javap. VERY IMCOMPLETE. */ +int flag_javap_compatible = 0; + +static int print_access_flags PROTO ((FILE *, uint16)); +static void print_constant_terse PROTO ((FILE*, JCF*, int, int)); +static void print_constant PROTO ((FILE *, JCF *, int, int)); +static void print_constant_ref PROTO ((FILE *, JCF *, int)); +static void disassemble_method PROTO ((JCF*, unsigned char *, int)); +static void print_name PROTO ((FILE*, JCF*, int)); +static void print_signature PROTO ((FILE*, JCF*, int, int)); + +#define PRINT_SIGNATURE_RESULT_ONLY 1 +#define PRINT_SIGNATURE_ARGS_ONLY 2 + +extern char* open_class(); + +int +DEFUN(utf8_equal_string, (jcf, index, value), + JCF *jcf AND int index AND char * value) +{ + if (CPOOL_INDEX_IN_RANGE (&jcf->cpool, index) + && JPOOL_TAG (jcf, index) == CONSTANT_Utf8) + { + int len = strlen (value); + if (JPOOL_UTF_LENGTH (jcf, index) == len + && memcmp (JPOOL_UTF_DATA (jcf, index), value, len) == 0) + return 1; + } + return 0; +} + +#define HANDLE_MAGIC(MAGIC, MINOR, MAJOR) \ + this_class_index = 0; \ + if (flag_print_class_info) \ + fprintf (out, \ + "Magic number: 0x%0x, minor_version: %d, major_version: %d.\n", \ + MAGIC, MINOR, MAJOR) + +#define HANDLE_START_CONSTANT_POOL(COUNT) \ + if (flag_print_constant_pool) \ + fprintf (out, "\nConstant pool (count: %d):\n", COUNT) + +#define HANDLE_SOURCEFILE(INDEX) \ +{ fprintf (out, "Attribute "); \ + print_constant_terse (out, jcf, attribute_name, CONSTANT_Utf8); \ + fprintf (out, ", length:%d, #%d=", attribute_length, INDEX); \ + print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8); fputc ('\n', out); } + +#define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \ + this_class_index = THIS; \ + class_access_flags = ACCESS_FLAGS; \ + if (flag_print_class_info) \ + { fprintf (out, "\nAccess flags: 0x%x", ACCESS_FLAGS); \ + print_access_flags (out, ACCESS_FLAGS); \ + fputc ('\n', out); \ + fprintf (out, "This class: "); \ + if (flag_print_constant_pool) \ + fprintf (out, "%d=", THIS); \ + print_constant_terse (out, jcf, THIS, CONSTANT_Class); \ + if (flag_print_constant_pool || SUPER != 0) \ + fprintf (out, ", super: "); \ + if (flag_print_constant_pool) \ + { \ + fprintf (out, "%d", SUPER); \ + if (SUPER != 0) \ + fputc ('=', out); \ + } \ + if (SUPER != 0) \ + print_constant_terse (out, jcf, SUPER, CONSTANT_Class); \ + fprintf (out, "\nInterfaces (count: %d):\n", INTERFACES_COUNT); \ + } + +#define IGNORE_ATTRIBUTE(JCF, NAME, NAME_LENGTH) \ + (flag_print_attributes <= 0) + +#define HANDLE_CLASS_INTERFACE(INDEX) \ + if (flag_print_class_info) \ + { fprintf (out, "- Implements: %d=", INDEX); \ + print_constant_terse (out, jcf, INDEX, CONSTANT_Class); \ + fputc ('\n', out); } + +#define HANDLE_START_FIELDS(FIELDS_COUNT) \ + if (flag_print_fields) \ + fprintf (out, "\nFields (count: %d):\n", FIELDS_COUNT) + +#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ + if (flag_print_fields) \ + { fprintf (out, "Field name:"); \ + print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \ + print_access_flags (out, ACCESS_FLAGS); \ + fprintf (out, " Signature: "); \ + if (flag_print_constant_pool) \ + fprintf (out, "%d=", SIGNATURE); \ + print_signature (out, jcf, SIGNATURE, 0); \ + fputc ('\n', out); } \ + else \ + flag_print_attributes--; + +#define HANDLE_END_FIELD() \ + if (! flag_print_fields) \ + flag_print_attributes++; + +#define HANDLE_START_METHODS(METHODS_COUNT) \ + if (flag_print_methods) \ + fprintf (out, "\nMethods (count: %d):\n", METHODS_COUNT); \ + else \ + flag_print_attributes--; + + +#define HANDLE_END_METHODS() \ + if (! flag_print_methods) \ + flag_print_attributes++; + +#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ +{ \ + if (flag_print_methods) \ + { \ + if (flag_javap_compatible) \ + { \ + fprintf (out, " "); \ + print_access_flags (out, ACCESS_FLAGS); \ + fputc (' ', out); \ + print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_RESULT_ONLY); \ + fputc (' ', out); \ + print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \ + print_signature (out, jcf, SIGNATURE, PRINT_SIGNATURE_ARGS_ONLY); \ + fputc ('\n', out); \ + } \ + else \ + { \ + fprintf (out, "\nMethod name:"); \ + print_constant_terse (out, jcf, NAME, CONSTANT_Utf8); \ + print_access_flags (out, ACCESS_FLAGS); \ + fprintf (out, " Signature: "); \ + if (flag_print_constant_pool) \ + fprintf (out, "%d=", SIGNATURE); \ + print_signature (out, jcf, SIGNATURE, 0); \ + fputc ('\n', out); \ + } \ + } \ + if (flag_print_main && ACCESS_FLAGS == (ACC_STATIC|ACC_PUBLIC) \ + && utf8_equal_string (jcf, NAME, "main") \ + && utf8_equal_string (jcf, SIGNATURE, "([Ljava/lang/String;)V") \ + && this_class_index > 0 \ + && (class_access_flags & ACC_PUBLIC)) \ + { \ + print_constant_terse(out, jcf, this_class_index, CONSTANT_Class); \ + fputc ('\n', out); \ + } \ +} + +#define COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH) \ +( fprintf (out, "Attribute "), \ + print_constant_terse (out, jcf, INDEX, CONSTANT_Utf8), \ + fprintf (out, ", length:%d", LENGTH) ) + +#define HANDLE_CONSTANTVALUE(VALUE_INDEX) \ +( COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length), \ + fprintf (out, ", value: "), \ + print_constant_ref (out, jcf, VALUE_INDEX), \ + fprintf (out, "\n") ) + +#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \ +{ COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \ + fprintf (out, ", max_stack:%d, max_locals:%d, code_length:%d\n", \ + MAX_STACK, MAX_LOCALS, CODE_LENGTH); \ + disassemble_method (jcf, jcf->read_ptr, CODE_LENGTH); } + +#define HANDLE_EXCEPTIONS_ATTRIBUTE(COUNT) \ +{ int n = (COUNT); int i; \ + COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \ + fprintf (out, ", count: %d\n", n); \ + for (i = 0; i < n; i++) {\ + int ex_index = JCF_readu2 (jcf); \ + fprintf (out, "%3d: ", i); \ + print_constant_ref (out, jcf, ex_index); \ + fputc ('\n', out); } } + +#define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \ +{ int n = (COUNT); int i; \ + COMMON_HANDLE_ATTRIBUTE(JCF, attribute_name, attribute_length); \ + fprintf (out, ", count: %d\n", n); \ + for (i = 0; i < n; i++) {\ + int start_pc = JCF_readu2 (jcf); \ + int length = JCF_readu2 (jcf); \ + int name_index = JCF_readu2 (jcf); \ + int signature_index = JCF_readu2 (jcf); \ + int slot = JCF_readu2 (jcf); \ + fprintf (out, " slot#%d: name: %d=", slot, name_index); \ + print_name (out, jcf, name_index); \ + fprintf (out, ", type: %d=", signature_index); \ + print_signature (out, jcf, signature_index, 0); \ + fprintf (out, " (pc: %d length: %d)\n", start_pc, length); }} + +#define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \ +{ int n = (COUNT); int i; \ + COMMON_HANDLE_ATTRIBUTE(jcf, attribute_name, attribute_length); \ + fprintf (out, ", count: %d\n", n); \ + if (flag_disassemble_methods) \ + for (i = 0; i < n; i++) {\ + int start_pc = JCF_readu2 (jcf); \ + int line_number = JCF_readu2 (jcf); \ + fprintf (out, " line: %d at pc: %d\n", line_number, start_pc); }\ + else \ + JCF_SKIP (jcf, 4 * n); } + +#define PROCESS_OTHER_ATTRIBUTE(JCF, INDEX, LENGTH) \ +{ COMMON_HANDLE_ATTRIBUTE(JCF, INDEX, LENGTH); \ + fputc ('\n', out); JCF_SKIP (JCF, LENGTH); } + +#define START_FINAL_ATTRIBUTES(ATTRIBUTES_COUNT) \ + if (flag_print_attributes > 0) \ + fprintf (out, "\nAttributes (count: %d):\n", attributes_count); + +#include "javaop.h" +#include "jcf-reader.c" + +static void +DEFUN(print_constant_ref, (stream, jcf, index), + FILE *stream AND JCF *jcf AND int index) +{ + fprintf (stream, "#%d=<", index); + if (index <= 0 || index >= JPOOL_SIZE(jcf)) + fprintf (stream, "out of range"); + else + print_constant (stream, jcf, index, 1); + fprintf (stream, ">", index); +} + +static int +DEFUN (print_access_flags, (stream, flags), + FILE *stream AND uint16 flags) +{ + if (flags & ACC_PUBLIC) fprintf (stream, " public"); + if (flags & ACC_PRIVATE) fprintf (stream, " private"); + if (flags & ACC_PROTECTED) fprintf (stream, " protected"); + if (flags & ACC_STATIC) fprintf (stream, " static"); + if (flags & ACC_FINAL) fprintf (stream, " final"); + if (flags & ACC_SYNCHRONIZED) fprintf (stream, " synchronized"); + if (flags & ACC_VOLATILE) fprintf (stream, " volatile"); + if (flags & ACC_TRANSIENT) fprintf (stream, " transient"); + if (flags & ACC_NATIVE) fprintf (stream, " native"); + if (flags & ACC_INTERFACE) fprintf (stream, " interface"); + if (flags & ACC_ABSTRACT) fprintf (stream, " abstract"); +} + + +static void +DEFUN(print_name, (stream, jcf, name_index), + FILE* stream AND JCF* jcf AND int name_index) +{ + if (JPOOL_TAG (jcf, name_index) != CONSTANT_Utf8) + fprintf (stream, ""); + else + jcf_print_utf8 (stream, JPOOL_UTF_DATA (jcf,name_index), + JPOOL_UTF_LENGTH (jcf, name_index)); +} + +/* If the type of the constant at INDEX matches EXPECTED, + print it tersely, otherwise more verbosely. */ + +void +DEFUN(print_constant_terse, (out, jcf, index, expected), + FILE *out AND JCF *jcf AND int index AND int expected) +{ + if (JPOOL_TAG (jcf, index) != expected) + { + fprintf (out, ""); + } + else + print_constant (out, jcf, index, 0); +} + +/* Print the constant at INDEX in JCF's constant pool. + If verbosity==0, print very tersely (no extraneous text). + If verbosity==1, prefix the type of the constant. + If verbosity==2, add more descriptive text. */ + +static void +DEFUN(print_constant, (out, jcf, index, verbosity), + FILE *out AND JCF *jcf AND int index AND int verbosity) +{ + int j, n; + jlong num; + char *str; + int kind = JPOOL_TAG (jcf, index); + switch (kind) + { + case CONSTANT_Class: + n = JPOOL_USHORT1 (jcf, index); + if (verbosity > 0) + fprintf (out, verbosity > 1 ? "Class name: %d=" : "Class ", n); + if (! CPOOL_INDEX_IN_RANGE (&jcf->cpool, n)) + fprintf (out, ""); + else if (verbosity < 2 && JPOOL_TAG (jcf, n) == CONSTANT_Utf8) + { + int len = JPOOL_UTF_LENGTH (jcf, n); + jcf_print_utf8_replace (out, JPOOL_UTF_DATA(jcf,n), len, '/', '.'); + } + else + print_constant_terse (out, jcf, n, CONSTANT_Utf8); + break; + case CONSTANT_Fieldref: + str = "Field"; goto field_or_method; + case CONSTANT_Methodref: + str = "Method"; goto field_or_method; + case CONSTANT_InterfaceMethodref: + str = "InterfaceMethod"; goto field_or_method; + field_or_method: + { + uint16 tclass = JPOOL_USHORT1 (jcf, index); + uint16 name_and_type = JPOOL_USHORT2 (jcf, index); + if (verbosity == 2) + fprintf (out, "%sref class: %d=", str, tclass); + else if (verbosity > 0) + fprintf (out, "%s ", str); + print_constant_terse (out, jcf, tclass, CONSTANT_Class); + fprintf (out, verbosity < 2 ? "." : " name_and_type: %d=<", + name_and_type); + print_constant_terse (out, jcf, name_and_type, CONSTANT_NameAndType); + if (verbosity == 2) + fputc ('>', out); + } + break; + case CONSTANT_String: + j = JPOOL_USHORT1 (jcf, index); + if (verbosity > 0) + fprintf (out, verbosity > 1 ? "String %d=" : "String ", j); + print_constant_terse (out, jcf, j, CONSTANT_Utf8); + break; + case CONSTANT_Integer: + if (verbosity > 0) + fprintf (out, "Integer "); + num = JPOOL_INT (jcf, index); + goto integer; + case CONSTANT_Long: + if (verbosity > 0) + fprintf (out, "Long "); + num = JPOOL_LONG (jcf, index); + goto integer; + integer: + { + char buffer[25]; + format_int (buffer, num, 10); + fprintf (out, "%s", buffer); + if (verbosity > 1) + { + format_uint (buffer, (uint64)num, 16); + fprintf (out, "=0x%s", buffer); + } + } + break; + case CONSTANT_Float: + { + jfloat fnum = JPOOL_FLOAT (jcf, index); + fprintf (out, "%s%.10g", verbosity > 1 ? "Float " : "", (double) fnum); + if (verbosity > 1) + fprintf (out, ", bits = 0x%08lx", (long) (* (int32 *) &fnum)); + break; + } + case CONSTANT_Double: + { + jdouble dnum = JPOOL_DOUBLE (jcf, index); + fprintf (out, "%s%.20g", verbosity > 1 ? "Double " : "", dnum); + if (verbosity > 1) + { + int32 hi, lo; + hi = JPOOL_UINT (jcf, index); + lo = JPOOL_UINT (jcf, index + 1); + fprintf (out, ", bits = 0x%08lx%08lx", (long) hi, (long) lo); + } + break; + } + case CONSTANT_NameAndType: + { + uint16 name = JPOOL_USHORT1 (jcf, index); + uint16 sig = JPOOL_USHORT2 (jcf, index); + if (verbosity > 0) + fprintf (out, verbosity > 1 ? "%s name: %d=" : "%s ", + "NameAndType", name); + print_name (out, jcf, name); + if (verbosity <= 1) + fputc (' ', out); + else + fprintf (out, ", signature: %d=", sig); + print_signature (out, jcf, sig, 0); + } + break; + case CONSTANT_Utf8: + { + register unsigned char *str = JPOOL_UTF_DATA (jcf, index); + int length = JPOOL_UTF_LENGTH (jcf, index); + if (verbosity > 0) + { /* Print as 8-bit bytes. */ + fputs ("Utf8: \"", out); + while (--length >= 0) + jcf_print_char (out, *str++); + } + else + { /* Print as Unicode. */ + fputc ('\"', out); + jcf_print_utf8 (out, str, length); + } + fputc ('\"', out); + } + break; + default: + fprintf (out, "(Unknown constant type %d)", kind); + } +} + +void +DEFUN(print_constant_pool, (jcf), + JCF *jcf) +{ + int i; + for (i = 1; i < JPOOL_SIZE(jcf); i++) + { + int kind = JPOOL_TAG (jcf, i); + fprintf (out, "#%d: ", i); + print_constant (out, jcf, i, 2); + fprintf (out, "\n"); + if (kind == CONSTANT_Double || kind == CONSTANT_Long) + i++; /* These take up two slots in the constant table */ + } +} + +static void +DEFUN(print_signature_type, (stream, ptr, limit), + FILE* stream AND const unsigned char **ptr AND const unsigned char *limit) +{ + int array_size; + if ((*ptr) >= limit) + return; + switch (*(*ptr)) + { + case '[': + array_size = -1; + for ((*ptr)++; (*ptr) < limit && isdigit (**ptr); (*ptr)++) + { + int digit = + array_size = (array_size < 0 ? 0 : 10 * array_size) + *(*ptr) - '0'; + } + print_signature_type (stream, ptr, limit); + if (array_size == -1) + fprintf (stream, "[]"); + else + fprintf (stream, "[%d]", array_size); + break; + case '(': + { + int nargs = 0; + fputc (*(*ptr)++, stream); + for (; **ptr != ')' && *ptr < limit; nargs++) + { + if (nargs > 0) + fputc (',', stream); + print_signature_type (stream, ptr, limit); + } + if (*ptr < limit) + { + fputc (*(*ptr)++, stream); + print_signature_type (stream, ptr, limit); + } + else + fprintf (stream, "???"); + } + break; + + case 'B': fprintf (stream, "byte"); (*ptr)++; break; + case 'C': fprintf (stream, "char"); (*ptr)++; break; + case 'D': fprintf (stream, "double"); (*ptr)++; break; + case 'F': fprintf (stream, "float"); (*ptr)++; break; + case 'S': fprintf (stream, "short"); (*ptr)++; break; + case 'I': fprintf (stream, "int"); (*ptr)++; break; + case 'J': fprintf (stream, "long"); (*ptr)++; break; + case 'Z': fprintf (stream, "boolean"); (*ptr)++; break; + case 'V': fprintf (stream, "void"); (*ptr)++; break; + + case 'L': + for ((*ptr)++; (*ptr)= limit) + fprintf (stream, ""); + else + { + if (options & PRINT_SIGNATURE_RESULT_ONLY) + { + while (str < limit && *str++ != ')') ; + } + if (options & PRINT_SIGNATURE_ARGS_ONLY) + { + *str++; + fputc ('(', stream); + while (str < limit && *str != ')') + { + print_signature_type (stream, &str, limit); + if (*str != ')') + fputs (", ", stream); + } + fputc (')', stream); + } + else + { + print_signature_type (stream, &str, limit); + if (str < limit) + { + fprintf (stream, "', stream); + } + } + } + } +} + +int +DEFUN (usage, (), ) +{ + fprintf (stderr, "Usage: jcf-dump [-o outputfile] [-c] classname\n"); + exit(1); +} + +void +DEFUN(process_class, (jcf), + JCF *jcf) +{ + int code; + if (jcf_parse_preamble (jcf) != 0) + fprintf (stderr, "Not a valid Java .class file.\n"); + + /* Parse and possibly print constant pool */ + code = jcf_parse_constant_pool (jcf); + if (code != 0) + { + fprintf (stderr, "error while parsing constant pool\n"); + exit (-1); + } + code = verify_constant_pool (jcf); + if (code > 0) + { + fprintf (stderr, "error in constant pool entry #%d\n", code); + exit (-1); + } + if (flag_print_constant_pool) + print_constant_pool (jcf); + + jcf_parse_class (jcf); + code = jcf_parse_fields (jcf); + if (code != 0) + { + fprintf (stderr, "error while parsing fields\n"); + exit (-1); + } + code = jcf_parse_methods (jcf); + if (code != 0) + { + fprintf (stderr, "error while parsing methods\n"); + exit (-1); + } + code = jcf_parse_final_attributes (jcf); + if (code != 0) + { + fprintf (stderr, "error while parsing final attributes\n"); + exit (-1); + } + jcf->filename = NULL; +} + +int +DEFUN(main, (argc, argv), + int argc AND char** argv) +{ + JCF jcf[1]; + int argi; + if (argc <= 1) + usage (); + + for (argi = 1; argi < argc; argi++) + { + char *arg = argv[argi]; + if (arg[0] == '-') + { + if (strcmp (arg, "-o") == 0 && argi + 1 < argc) + output_file = argv[++argi]; + else if (arg[1] == '-') + { + arg++; + if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc) + classpath = argv[++argi]; + else if (strcmp (arg, "-verbose") == 0) + verbose++; + else if (strcmp (arg, "-print-main") == 0) + flag_print_main++; + else if (strcmp (arg, "-javap") == 0) + { + flag_javap_compatible++; + flag_print_constant_pool = 0; + } + else if (arg[2] == '\0') + break; + else + { + fprintf (stderr, "%s: illegal argument\n", argv[argi]); + exit (-1); + } + + } + else if (strcmp (arg, "-classpath") == 0 && argi + 1 < argc) + classpath = argv[++argi]; + else if (strcmp (arg, "-verbose") == 0) + verbose++; + else if (strcmp (arg, "-print-main") == 0) + flag_print_main++; + else if (strcmp (arg, "-c") == 0) + flag_disassemble_methods++; + else + { + fprintf (stderr, "%s: illegal argument\n", argv[argi]); + exit (-1); + } + } + else + break; + } + if (argi == argc) + usage (); + if (flag_print_main) + { + flag_print_fields = 0; + flag_print_methods = 0; + flag_print_constant_pool = 0; + flag_print_attributes = 0; + flag_print_class_info = 0; + } + + if (classpath == NULL) + { + classpath = (char *) getenv ("CLASSPATH"); + if (classpath == NULL) + classpath = ""; + } + + if (output_file) + { + out = fopen (output_file, "w"); + if (out) + { + fprintf (stderr, "Cannot open '%s' for output.\n", output_file); + exit (-1); + } + } + else + out = stdout; + + if (argi >= argc) + { + fprintf (out, "Reading .class from .\n"); +#if JCF_USE_STDIO + open_class ("", jcf, stdin); +#else + open_class ("", jcf, 0); +#endif + process_class (jcf); + } + else + { + for (; argi < argc; argi++) + { + char *arg = argv[argi]; + char* class_filename = find_class (arg, strlen (arg), jcf, 1); + if (class_filename == NULL) + class_filename = find_classfile (arg, jcf); + if (class_filename == NULL) + { + perror ("Could not find class"); + exit (-1); + } + JCF_FILL (jcf, 4); + if (GET_u4 (jcf->read_ptr) == ZIPMAGIC) + { + long compressed_size, member_size; + int compression_method, filename_length, extra_length; + int general_purpose_bits; + char *filename; + int total_length; + if (flag_print_class_info) + fprintf (out, "Reading classes from archive %s.\n", + class_filename); + for (;;) + { + int skip = 0; + jcf_filbuf_t save_filbuf = jcf->filbuf; + long magic = JCF_readu4_le (jcf); + if (magic == 0x02014b50 || magic == 0x06054b50) + break; /* got to central directory */ + if (magic != 0x04034b50) /* ZIPMAGIC (little-endian) */ + { + fprintf (stderr, "bad format of .zip archine\n"); + exit (-1); + } + JCF_FILL (jcf, 26); + JCF_SKIP (jcf, 2); + general_purpose_bits = JCF_readu2_le (jcf); + compression_method = JCF_readu2_le (jcf); + JCF_SKIP (jcf, 8); + compressed_size = JCF_readu4_le (jcf); + member_size = JCF_readu4_le (jcf); + filename_length = JCF_readu2_le (jcf); + extra_length = JCF_readu2_le (jcf); + total_length = filename_length + extra_length + + compressed_size; + if (jcf->read_end - jcf->read_ptr < total_length) + jcf_trim_old_input (jcf); + JCF_FILL (jcf, total_length); + filename = jcf->read_ptr; + JCF_SKIP (jcf, filename_length); + JCF_SKIP (jcf, extra_length); + if (filename_length > 0 + && filename[filename_length-1] == '/') + { + if (flag_print_class_info) + fprintf (out, "[Skipping directory %.*s]\n", + filename_length, filename); + skip = 1; + } + else if (compression_method != 0) + { + if (flag_print_class_info) + fprintf (out, "[Skipping compressed file %.*s]\n", + filename_length, filename); + skip = 1; + } + else if (member_size < 4 + || GET_u4 (jcf->read_ptr) != 0xcafebabe) + { + if (flag_print_class_info) + fprintf (out, "[Skipping non-.class member %.*s]\n", + filename_length, filename); + skip = 1; + } + else + { + if (flag_print_class_info) + fprintf (out, "Reading class member: %.*s.\n", + filename_length, filename); + } + if (skip) + { + JCF_SKIP (jcf, compressed_size); + } + else + { + unsigned char *save_end; + jcf->filbuf = jcf_unexpected_eof; + save_end = jcf->read_end; + jcf->read_end = jcf->read_ptr + compressed_size; + process_class (jcf); + jcf->filbuf = save_filbuf; + jcf->read_end = save_end; + } + } + } + else + { + if (flag_print_class_info) + fprintf (out, "Reading .class from %s.\n", class_filename); + process_class (jcf); + } + JCF_FINISH(jcf); + } + } +} + +static void +DEFUN(disassemble_method, (jcf, byte_ops, len), + JCF* jcf AND unsigned char *byte_ops AND int len) +{ +#undef AND /* Causes problems with opcodes for iand and land. */ +#undef PTR + int PC; + int i; + if (flag_disassemble_methods == 0) + return; +#define BCODE byte_ops + for (PC = 0; PC < len;) + { + int oldpc = PC; + int saw_index; + jlong LONG_temp; + jint INT_temp; + jfloat FLOAT_temp; + jdouble DOUBLE_temp; + switch (byte_ops[PC++]) + { + +/* This is the actual code emitted for each of opcodes in javaops.def. + The actual opcode-specific stuff is handled by the OPKIND macro. + I.e. for an opcode whose OPKIND is BINOP, the BINOP will be called. + Those macros are defiend below. The OPKINDs that do not have any + inline parameters (such as BINOP) and therefore do mot need anything + else to me printed out just use an empty body. */ + +#define JAVAOP(OPNAME, OPCODE, OPKIND, OPERAND_TYPE, OPERAND_VALUE) \ + case OPCODE: \ + fprintf (out, "%3d: %s", oldpc, #OPNAME); \ + OPKIND(OPERAND_TYPE, OPERAND_VALUE); \ + fputc ('\n', out); \ + break; + +#define CONST_INDEX_1 (saw_index = 1, IMMEDIATE_u1) +#define CONST_INDEX_2 (saw_index = 1, IMMEDIATE_u2) +#define VAR_INDEX_1 (saw_index = 1, IMMEDIATE_u1) +#define VAR_INDEX_2 (saw_index = 1, IMMEDIATE_u2) + +#define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > len ? \ + (fprintf(stderr, "Bad byte codes.\n"), exit(-1)) : 1) + +/* Print out operand (if not implied by the opcode) for PUSCH opcodes. + These all push a constant onto the opcode stack. */ +#define PUSHC(OPERAND_TYPE, OPERAND_VALUE) \ + saw_index = 0, INT_temp = (OPERAND_VALUE); \ + if (oldpc+1 == PC) /* nothing */; \ + else if (saw_index) fprintf (out, " "), print_constant_ref (out, jcf, INT_temp); \ + else fprintf (out, " %d", INT_temp); + +/* Print out operand (a local variable index) for LOAD opcodes. + These all push local variable onto the opcode stack. */ +#define LOAD(OPERAND_TYPE, OPERAND_VALUE) \ + INT_temp = (OPERAND_VALUE); \ + if (oldpc+1 == PC) /* nothing - local index implied by opcode */; \ + else fprintf (out, " %d", INT_temp); + +/* Handle STORE opcodes same as LOAD opcodes. + These all store a value from the opcode stack in a local variable. */ +#define STORE LOAD + +/* Handle more kind of opcodes. */ +#define STACK(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define UNOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define BINOP(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define CONVERT(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define CONVERT2(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define RETURN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ +#define UNKNOWN(OPERAND_TYPE, OPERAND_VALUE) /* nothing */ + +/* Handle putfield and getfield opcodes, with static versions. */ +#define FIELD(MAYBE_STATIC, PUT_OR_GET) \ + fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2) + +/* Print operand for invoke opcodes. */ +#define INVOKE(OPERAND_TYPE, OPERAND_VALUE) \ + fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2);\ + PC += 2 * OPERAND_VALUE /* for invokeinterface */; + +#define OBJECT(OPERAND_TYPE, OPERAND_VALUE) \ + fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); + +#define ARRAY(OPERAND_TYPE, SUBOP) \ + ARRAY_##SUBOP(OPERAND_TYPE) +/* Handle sub-categories of ARRAY opcodes. */ +#define ARRAY_LOAD(TYPE) /* nothing */ +#define ARRAY_STORE(TYPE) /* nothing */ +#define ARRAY_LENGTH(TYPE) /* nothing */ +#define ARRAY_NEW(TYPE) ARRAY_NEW_##TYPE +#define ARRAY_NEW_NUM \ + INT_temp = IMMEDIATE_u1; \ + { char *str; \ + switch (INT_temp) { \ + case 4: str = "boolean"; break; \ + case 5: str = "char"; break; \ + case 6: str = "float"; break; \ + case 7: str = "double"; break; \ + case 8: str = "byte"; break; \ + case 9: str = "short"; break; \ + case 10: str = "int"; break; \ + case 11: str = "long"; break; \ + default: str = ""; break; \ + } \ + fputc (' ', out); fprintf (out, str, INT_temp); } + +#define ARRAY_NEW_PTR \ + fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); + +#define ARRAY_NEW_MULTI \ + fputc (' ', out); print_constant_ref (out, jcf, IMMEDIATE_u2); \ + fprintf (out, " %d", IMMEDIATE_u1); /* number of dimensions */ + +#define TEST(OPERAND_TYPE, OPERAND_VALUE) \ + fprintf (out, " %d", oldpc + IMMEDIATE_s2) + +#define BRANCH(OPERAND_TYPE, OPERAND_VALUE) \ + saw_index = 0, INT_temp = (OPERAND_VALUE); \ + fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp) + +#define JSR(OPERAND_TYPE, OPERAND_VALUE) \ + saw_index = 0, INT_temp = (OPERAND_VALUE); \ + fprintf (out, " %d", saw_index ? INT_temp : oldpc + INT_temp) + +#define RET(OPERAND_TYPE, OPERAND_VALUE) \ + INT_temp = (OPERAND_VALUE); \ + fprintf (out, " %d", INT_temp); + +#define SWITCH(OPERAND_TYPE, TABLE_OR_LOOKUP) \ + PC = (PC + 3) / 4 * 4; TABLE_OR_LOOKUP##_SWITCH + +#define LOOKUP_SWITCH \ + { jint default_offset = IMMEDIATE_s4; jint npairs = IMMEDIATE_s4; \ + fprintf (out, " npairs=%d, default=%d", npairs, default_offset+oldpc); \ + while (--npairs >= 0) { \ + jint match = IMMEDIATE_s4; jint offset = IMMEDIATE_s4; \ + fprintf (out, "\n%10ld: %ld", (long)match, (long)(offset+oldpc)); } \ + } + +#define TABLE_SWITCH \ + { jint default_offset = IMMEDIATE_s4; \ + jint low = IMMEDIATE_s4; jint high = IMMEDIATE_s4; \ + fprintf (out, " low==%d, high=%ddefault=%d", \ + low, high, default_offset+oldpc); \ + for (; low <= high; low++) { \ + jint offset = IMMEDIATE_s4; \ + fprintf (out, "\n%10ld: %ld", (long)low, (long)(offset+oldpc)); } \ + } + +#define SPECIAL(OPERAND_TYPE, OPERAND_VALUE) \ + SPECIAL_##OPERAND_VALUE(OPERAND_TYPE) + +#define SPECIAL_IINC(OPERAND_TYPE) \ + INT_temp = IMMEDIATE_u1; \ + fprintf (out, "%d %d", INT_temp, IMMEDIATE_s1) + +#define SPECIAL_WIDE(OPERAND_TYPE) \ + INT_temp = IMMEDIATE_u1; fprintf (out, "%d", INT_temp) + +#define SPECIAL_EXIT(OPERAND_TYPE) /* nothing */ +#define SPECIAL_ENTER(OPERAND_TYPE) /* nothing */ +#define SPECIAL_BREAK(OPERAND_TYPE) /* nothing */ +#define SPECIAL_THROW(OPERAND_TYPE) /* nothing */ + +#define IMPL(OPERAND_TYPE, OPERAND_VALUE) \ + fprintf (out, " %d", IMMEDIATE_u##OPERAND_VALUE) + +#define COND(OPERAND_TYPE, OPERAND_VALUE) \ + TEST(OPERAND_TYPE, OPERAND_VALUE) + +#include "javaop.def" + default: + fprintf (out, "%3d: unknown(%3d)\n", oldpc, byte_ops[PC]); + } + } + + /* Print exception table. */ + i = GET_u2(byte_ops+len); + if (i > 0) + { + unsigned char *ptr = byte_ops+len+2; + fprintf (out, "Exceptions (count: %d):\n", i); + for (; --i >= 0; ptr+= 8) + { + int start_pc = GET_u2 (ptr); + int end_pc = GET_u2 (ptr+2); + int handler_pc = GET_u2 (ptr+4); + int catch_type = GET_u2 (ptr+6); + fprintf (out, " start: %d, end: %d, handler: %d, type: %d", + start_pc, end_pc, handler_pc, catch_type); + if (catch_type == 0) + fputs (" /* finally */", out); + else + { + fputc('=', out); + print_constant_terse (out, jcf, catch_type, CONSTANT_Class); + } + fputc ('\n', out); + } + } +} diff --git a/gcc/java/jcf-io.c b/gcc/java/jcf-io.c new file mode 100644 index 00000000000..931f34eaec5 --- /dev/null +++ b/gcc/java/jcf-io.c @@ -0,0 +1,574 @@ +/* Utility routines for finding and reading Java(TM) .class files. + Copyright (C) 1996 Free Software Foundation, Inc. + +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, 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 GNU CC; 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. */ + +/* Written by Per Bothner , February 1996. */ + +#include + +#define ENABLE_UNZIP 1 + +#include "jcf.h" +#ifdef __STDC__ +#include +#endif +#include +#include +#include +#include +#include + +/* DOS brain-damage */ +#ifndef O_BINARY +#define O_BINARY 0 /* MS-DOS brain-damage */ +#endif + +char *classpath; + +int +DEFUN(jcf_unexpected_eof, (jcf, count), + JCF *jcf AND int count) +{ + if (jcf->filename) + fprintf (stderr, "Premature end of .class file %s.\n", jcf->filename); + else + fprintf (stderr, "Premature end of .class file .\n"); + exit (-1); +} + +void +DEFUN(jcf_trim_old_input, (jcf), + JCF *jcf) +{ + int count = jcf->read_ptr - jcf->buffer; + if (count > 0) + { + memmove (jcf->buffer, jcf->read_ptr, jcf->read_end - jcf->read_ptr); + jcf->read_ptr -= count; + jcf->read_end -= count; + } +} + +int +DEFUN(jcf_filbuf_from_stdio, (jcf, count), + JCF *jcf AND int count) +{ + FILE *file = (FILE*) (jcf->read_state); + if (count > jcf->buffer_end - jcf->read_ptr) + { + JCF_u4 old_read_ptr = jcf->read_ptr - jcf->buffer; + JCF_u4 old_read_end = jcf->read_end - jcf->buffer; + JCF_u4 old_size = jcf->buffer_end - jcf->buffer; + JCF_u4 new_size = (old_size == 0 ? 2000 : 2 * old_size) + count; + unsigned char *new_buffer = jcf->buffer == NULL ? ALLOC (new_size) + : REALLOC (jcf->buffer, new_size); + jcf->buffer = new_buffer; + jcf->buffer_end = new_buffer + new_size; + jcf->read_ptr = new_buffer + old_read_ptr; + jcf->read_end = new_buffer + old_read_end; + } + count -= jcf->read_end - jcf->read_ptr; + if (count <= 0) + return 0; + if (fread (jcf->read_end, 1, count, file) != count) + jcf_unexpected_eof (jcf, count); + jcf->read_end += count; + return 0; +} + +#if ENABLE_UNZIP +#include "zipfile.h" + +struct ZipFileCache *SeenZipFiles = NULL; + +int +DEFUN(open_in_zip, (jcf, +zipfile, zipmember), + JCF *jcf AND const char *zipfile AND const char *zipmember) +{ + struct ZipFileCache* zipf; + ZipDirectory *zipd; + int i, len; + for (zipf = SeenZipFiles; ; zipf = zipf->next) + { + if (zipf == NULL) + { + char magic [4]; + int fd = open (zipfile, O_RDONLY | O_BINARY); + if (read (fd, magic, 4) != 4 || GET_u4 (magic) != (JCF_u4)ZIPMAGIC) + return -1; + lseek (fd, 0L, SEEK_SET); + zipf = ALLOC (sizeof (struct ZipFileCache) + strlen (zipfile) + 1); + zipf->next = SeenZipFiles; + zipf->name = (char*)(zipf+1); + strcpy (zipf->name, zipfile); + SeenZipFiles = zipf; + zipf->z.fd = fd; + if (fd == -1) + { + /* A missing zip file is not considered an error. */ + zipf->z.count = 0; + zipf->z.dir_size = 0; + zipf->z.central_directory = NULL; + return -1; + } + else + { + if (read_zip_archive (&zipf->z) != 0) + return -2; /* This however should be an error - FIXME */ + } + break; + } + if (strcmp (zipf->name, zipfile) == 0) + break; + } + + if (!zipmember) + return 0; + + len = strlen (zipmember); + + zipd = (struct ZipDirectory*) zipf->z.central_directory; + for (i = 0; i < zipf->z.count; i++, zipd = ZIPDIR_NEXT (zipd)) + { + if (len == zipd->filename_length && + strncmp (ZIPDIR_FILENAME (zipd), zipmember, len) == 0) + { + JCF_ZERO (jcf); + jcf->buffer = ALLOC (zipd->size); + jcf->buffer_end = jcf->buffer + zipd->size; + jcf->read_ptr = jcf->buffer; + jcf->read_end = jcf->buffer_end; + jcf->filbuf = jcf_unexpected_eof; + jcf->filename = (char *) strdup (zipfile); + jcf->classname = (char *) strdup (zipmember); + jcf->zipd = (void *)zipd; + if (lseek (zipf->z.fd, zipd->filestart, 0) < 0 + || read (zipf->z.fd, jcf->buffer, zipd->size) != zipd->size) + return -2; + return 0; + } + } + return -1; +} +#endif /* ENABLE_UNZIP */ + +#if JCF_USE_STDIO +char* +DEFUN(open_class, (filename, jcf, stream), + char *filename AND JCF *jcf AND FILE* stream) +{ + if (jcf) + { + JCF_ZERO (jcf); + jcf->buffer = NULL; + jcf->buffer_end = NULL; + jcf->read_ptr = NULL; + jcf->read_end = NULL; + jcf->read_state = stream; + jcf->filbuf = jcf_filbuf_from_stdio; + } + else + fclose (stream); + return filename; +} +#else +char* +DEFUN(open_class, (filename, jcf, fd), + char *filename AND JCF *jcf AND int fd) +{ + if (jcf) + { + struct stat stat_buf; + if (fstat (fd, &stat_buf) != 0 + || ! S_ISREG (stat_buf.st_mode)) + { + perror ("Could not figure length of .class file"); + return NULL; + } + JCF_ZERO (jcf); + jcf->buffer = ALLOC (stat_buf.st_size); + jcf->buffer_end = jcf->buffer + stat_buf.st_size; + jcf->read_ptr = jcf->buffer; + jcf->read_end = jcf->buffer_end; + jcf->read_state = NULL; + jcf->filename = filename; + if (read (fd, jcf->buffer, stat_buf.st_size) != stat_buf.st_size) + { + perror ("Failed to read .class file"); + return NULL; + } + close (fd); + jcf->filbuf = jcf_unexpected_eof; + } + else + close (fd); + return filename; +} +#endif + + +char * +DEFUN(find_classfile, (filename_length, jcf), + char *filename AND JCF *jcf) +{ +#if JCF_USE_STDIO + FILE *stream = fopen (filename, "rb"); + if (stream == NULL) + return NULL; + return open_class (arg, jcf, stream); +#else + int fd = open (filename, O_RDONLY | O_BINARY); + if (fd < 0) + return NULL; + return open_class (filename, jcf, fd); +#endif +} + +/* Returns a freshly malloc'd string with the fully qualified pathname + of the .class file for the class CLASSNAME. Returns NULL on + failure. If JCF != NULL, it is suitably initialized. With + DO_CLASS_FILE set to 1, search a .class/.java file named after + CLASSNAME, otherwise, search a ZIP directory entry named after + CLASSNAME. */ + +char * +DEFUN(find_class, (classname, classname_length, jcf, do_class_file), + const char *classname AND int classname_length AND JCF *jcf AND int do_class_file) + +{ +#if JCF_USE_STDIO + FILE *stream; +#else + int fd; +#endif + int i, j, k, java, class; + struct stat java_buf, class_buf; + + /* Allocate and zero out the buffer, since we don't explicitly put a + null pointer when we're copying it below. */ + int buflen = strlen (classpath) + classname_length + 10; + char *buffer = (char *) ALLOC (buflen); + bzero (buffer, buflen); + + jcf->java_source = jcf->outofsynch = 0; + for (j = 0; classpath[j] != '\0'; ) + { + for (i = 0; classpath[j] != ':' && classpath[j] != '\0'; i++, j++) + buffer[i] = classpath[j]; + if (classpath[j] == ':') + j++; + if (i > 0) /* Empty directory is redundant */ + { + int dir_len; + if (buffer[i-1] != '/') + buffer[i++] = '/'; + dir_len = i-1; + for (k = 0; k < classname_length; k++, i++) + { + char ch = classname[k]; + buffer[i] = ch == '.' ? '/' : ch; + } + if (do_class_file) + strcpy (buffer+i, ".class"); +#if ENABLE_UNZIP + if (dir_len > 4 + && buffer[dir_len-4] == '.' && buffer[dir_len-3] == 'z' + && buffer[dir_len-2] == 'i' && buffer[dir_len-1] == 'p') + { + int err_code; + JCF _jcf; + if (!do_class_file) + strcpy (buffer+i, "/"); + buffer[dir_len] = '\0'; + if (do_class_file) + SOURCE_FRONTEND_DEBUG + (("Trying [...%s]:%s", + &buffer[dir_len-(dir_len > 15 ? 15 : dir_len)], + buffer+dir_len+1)); + if (jcf == NULL) + jcf = &_jcf; + err_code = open_in_zip (jcf, buffer, buffer+dir_len+1); + if (err_code == 0) + { + if (!do_class_file) + jcf->seen_in_zip = 1; + else + { + buffer[dir_len] = '('; + strcpy (buffer+i, ".class)"); + } + if (jcf == &_jcf) + JCF_FINISH (jcf); + return buffer; + } + else + continue; + } +#endif + /* If we do directories, do them here */ + if (!do_class_file) + { + struct stat dir_buff; + int dir; + buffer[i] = '\0'; /* Was previously unterminated here. */ + if (!(dir = stat (buffer, &dir_buff))) + { + jcf->seen_in_zip = 0; + goto found; + } + } + + /* Check for out of synch .class/.java files */ + class = stat (buffer, &class_buf); + strcpy (buffer+i, ".java"); + java = stat (buffer, &java_buf); + if ((!java && !class) && java_buf.st_mtime >= class_buf.st_mtime) + jcf->outofsynch = 1; +#if JCF_USE_STDIO + if (!class) + { + strcpy (buffer+i, ".class"); + SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); + stream = fopen (buffer, "rb"); + if (stream) + goto found; + } + /* Give .java a try, if necessary */ + if (!java) + { + strcpy (buffer+i, ".java"); + SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); + stream = fopen (buffer, "r"); + if (stream) + { + jcf->java_source = 1; + goto found; + } + } +#else + if (!class) + { + strcpy (buffer+i, ".class"); + SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); + fd = open (buffer, O_RDONLY | O_BINARY); + if (fd >= 0) + goto found; + } + /* Give .java a try, if necessary */ + if (!java) + { + if (do_class_file) + strcpy (buffer+i, ".java"); + SOURCE_FRONTEND_DEBUG (("Trying %s", buffer)); + fd = open (buffer, O_RDONLY | O_BINARY); + if (fd >= 0) + { + jcf->java_source = 1; + goto found; + } + } +#endif + } + } + free (buffer); + return NULL; + found: +#if JCF_USE_STDIO + if (jcf->java_source) + return NULL; /* FIXME */ + else + return open_class (buffer, jcf, stream); +#else + if (jcf->java_source) + { + JCF_ZERO (jcf); /* JCF_FINISH relies on this */ + jcf->java_source = 1; + jcf->filename = (char *) strdup (buffer); + close (fd); /* We use STDIO for source file */ + } + else if (do_class_file) + buffer = open_class (buffer, jcf, fd); + jcf->classname = (char *) ALLOC (classname_length + 1); + strncpy (jcf->classname, classname, classname_length + 1); + jcf->classname = (char *) strdup (classname); + return buffer; +#endif +} + +void +DEFUN(jcf_print_char, (stream, ch), + FILE *stream AND int ch) +{ + switch (ch) + { + case '\'': + case '\\': + case '\"': + fprintf (stream, "\\%c", ch); + break; + case '\n': + fprintf (stream, "\\n"); + break; + case '\t': + fprintf (stream, "\\t"); + break; + case '\r': + fprintf (stream, "\\r"); + break; + default: + if (ch >= ' ' && ch < 127) + putc (ch, stream); + else if (ch < 256) + fprintf (stream, "\\%03x", ch); + else + fprintf (stream, "\\u%04x", ch); + } +} + +/* Print UTF8 string at STR of length LENGTH bytes to STREAM. */ + +void +DEFUN(jcf_print_utf8, (stream, str, length), + FILE *stream AND register unsigned char *str AND int length) +{ + unsigned char* limit = str + length; + while (str < limit) + { + int ch = UTF8_GET (str, limit); + if (ch < 0) + { + fprintf (stream, "\\"); + return; + } + jcf_print_char (stream, ch); + } +} + +/* Same as jcf_print_utf8, but print IN_CHAR as OUT_CHAR. */ + +void +DEFUN(jcf_print_utf8_replace, (stream, str, length, in_char, out_char), + FILE *stream AND unsigned char *str AND int length + AND int in_char AND int out_char) +{ + + int i;/* FIXME - actually handle Unicode! */ + for (i = 0; i < length; i++) + { + int ch = str[i]; + jcf_print_char (stream, ch == in_char ? out_char : ch); + } +} + +/* Check that all the cross-references in the constant pool are + valid. Returns 0 on success. + Otherwise, returns the index of the (first) invalid entry. */ + +int +DEFUN(verify_constant_pool, (jcf), + JCF *jcf) +{ + int i, n; + for (i = 1; i < JPOOL_SIZE (jcf); i++) + { + switch (JPOOL_TAG (jcf, i)) + { + case CONSTANT_NameAndType: + n = JPOOL_USHORT2 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) + return i; + /* ... fall through ... */ + case CONSTANT_Class: + case CONSTANT_String: + n = JPOOL_USHORT1 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_Utf8) + return i; + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + n = JPOOL_USHORT1 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_Class) + return i; + n = JPOOL_USHORT2 (jcf, i); + if (n <= 0 || n >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, n) != CONSTANT_NameAndType) + return i; + break; + case CONSTANT_Long: + case CONSTANT_Double: + i++; + break; + case CONSTANT_Float: + case CONSTANT_Integer: + case CONSTANT_Utf8: + case CONSTANT_Unicode: + break; + default: + return i; + } + } + return 0; +} + +void +DEFUN(format_uint, (buffer, value, base), + char *buffer AND uint64 value AND int base) +{ +#define WRITE_BUF_SIZE (4 + sizeof(uint64) * 8) + char buf[WRITE_BUF_SIZE]; + register char *buf_ptr = buf+WRITE_BUF_SIZE; /* End of buf. */ + int chars_written; + int i; + + /* Now do the actual conversion, placing the result at the *end* of buf. */ + /* Note this code does not pretend to be optimized. */ + do { + int digit = value % base; + static char digit_chars[] = "0123456789abcdefghijklmnopqrstuvwxyz"; + *--buf_ptr = digit_chars[digit]; + value /= base; + } while (value != 0); + + chars_written = buf+WRITE_BUF_SIZE - buf_ptr; + for (i = 0; i < chars_written; i++) + buffer[i] = *buf_ptr++; + buffer[i] = 0; +} + +void +DEFUN(format_int, (buffer, value, base), + char *buffer AND jlong value AND int base) +{ + uint64 abs_value; + if (value < 0) + { + abs_value = -(uint64)value; + *buffer++ = '-'; + } + else + abs_value = (uint64) value; + format_uint (buffer, abs_value, base); +} diff --git a/gcc/java/jcf-parse.c b/gcc/java/jcf-parse.c new file mode 100644 index 00000000000..0e8c51ccbde --- /dev/null +++ b/gcc/java/jcf-parse.c @@ -0,0 +1,917 @@ +/* Parser for Java(TM) .class files. + Copyright (C) 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Written by Per Bothner */ + +#include +#include +#include "config.h" +#include "tree.h" +#include "obstack.h" +#include "flags.h" +#include "java-except.h" +#include "input.h" +#include "java-tree.h" + +/* A CONSTANT_Utf8 element is converted to an IDENTIFIER_NODE at parse time. */ +#define JPOOL_UTF(JCF, INDEX) CPOOL_UTF(&(JCF)->cpool, INDEX) +#define JPOOL_UTF_LENGTH(JCF, INDEX) IDENTIFIER_LENGTH (JPOOL_UTF (JCF, INDEX)) +#define JPOOL_UTF_DATA(JCF, INDEX) \ + ((unsigned char*) IDENTIFIER_POINTER (JPOOL_UTF (JCF, INDEX))) +#define HANDLE_CONSTANT_Utf8(JCF, INDEX, LENGTH) \ + do { \ + unsigned char save; unsigned char *text; \ + JCF_FILL (JCF, (LENGTH)+1); /* Make sure we read 1 byte beyond string. */ \ + text = (JCF)->read_ptr; \ + save = text[LENGTH]; \ + text[LENGTH] = 0; \ + (JCF)->cpool.data[INDEX] = (jword) get_identifier (text); \ + text[LENGTH] = save; \ + JCF_SKIP (JCF, LENGTH); } while (0) + +#include "jcf.h" +#ifdef __STDC__ +/* For getenv */ +#include +#endif + +#ifndef SEEK_SET +#include +#endif + +extern struct obstack *saveable_obstack; +extern struct obstack temporary_obstack; +extern struct obstack permanent_obstack; + +/* The class we are currently processing. */ +tree current_class = NULL_TREE; + +/* The class we started with. */ +tree main_class = NULL_TREE; + +/* The FIELD_DECL for the current field. */ +static tree current_field = NULL_TREE; + +static tree current_method = NULL_TREE; + +static tree give_name_to_class PROTO ((JCF *jcf, int index)); + +void parse_zip_file_entries (void); +void process_zip_dir(); + +/* Source file compilation declarations */ +static void parse_source_file (); +extern int java_error_count; +#define java_parse_abort_on_error() \ + { \ + if (java_error_count) \ + { \ + java_report_errors (); \ + java_pop_parser_context (); \ + return; \ + } \ + } + +/* Handle "SourceFile" attribute. */ + +void +set_source_filename (jcf, index) + JCF *jcf; + int index; +{ + tree sfname_id = get_name_constant (jcf, index); + char *sfname = IDENTIFIER_POINTER (sfname_id); + if (input_filename != NULL) + { + int old_len = strlen (input_filename); + int new_len = IDENTIFIER_LENGTH (sfname_id); + /* Use the current input_filename (derived from the class name) + if it has a directory prefix, but otherwise matches sfname. */ + if (old_len > new_len + && strcmp (sfname, input_filename + old_len - new_len) == 0 + && (input_filename[old_len - new_len - 1] == '/' + || input_filename[old_len - new_len - 1] == '\\')) + return; + } + input_filename = sfname; + DECL_SOURCE_FILE (TYPE_NAME (current_class)) = sfname; + if (current_class == main_class) main_input_filename = input_filename; +} + +#define HANDLE_SOURCEFILE(INDEX) set_source_filename (jcf, INDEX) + +#define HANDLE_CLASS_INFO(ACCESS_FLAGS, THIS, SUPER, INTERFACES_COUNT) \ +{ tree super_class = SUPER==0 ? NULL_TREE : get_class_constant (jcf, SUPER); \ + current_class = give_name_to_class (jcf, THIS); \ + set_super_info (ACCESS_FLAGS, current_class, super_class, INTERFACES_COUNT);} + +#define HANDLE_CLASS_INTERFACE(INDEX) \ + add_interface (current_class, get_class_constant (jcf, INDEX)) + +#define HANDLE_START_FIELD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ +{ int sig_index = SIGNATURE; \ + current_field = add_field (current_class, get_name_constant (jcf, NAME), \ + parse_signature (jcf, sig_index), ACCESS_FLAGS); \ + set_java_signature (TREE_TYPE (current_field), JPOOL_UTF (jcf, sig_index)); } + +#define HANDLE_END_FIELDS() \ + (current_field = NULL_TREE) + +#define HANDLE_CONSTANTVALUE(INDEX) \ +{ tree constant; int index = INDEX; \ + if (JPOOL_TAG (jcf, index) == CONSTANT_String) { \ + tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); \ + constant = build_utf8_ref (name); \ + } \ + else \ + constant = get_constant (jcf, index); \ + set_constant_value (current_field, constant); } + +#define HANDLE_METHOD(ACCESS_FLAGS, NAME, SIGNATURE, ATTRIBUTE_COUNT) \ + (current_method = add_method (current_class, ACCESS_FLAGS, \ + get_name_constant (jcf, NAME), \ + get_name_constant (jcf, SIGNATURE)), \ + DECL_LOCALVARIABLES_OFFSET (current_method) = 0, \ + DECL_LINENUMBERS_OFFSET (current_method) = 0) + +#define HANDLE_END_METHODS() \ +{ tree handle_type = CLASS_TO_HANDLE_TYPE (current_class); \ + if (handle_type != current_class) layout_type (handle_type); } + +#define HANDLE_CODE_ATTRIBUTE(MAX_STACK, MAX_LOCALS, CODE_LENGTH) \ +{ DECL_MAX_STACK (current_method) = (MAX_STACK); \ + DECL_MAX_LOCALS (current_method) = (MAX_LOCALS); \ + DECL_CODE_LENGTH (current_method) = (CODE_LENGTH); \ + DECL_CODE_OFFSET (current_method) = JCF_TELL (jcf); } + +#define HANDLE_LOCALVARIABLETABLE_ATTRIBUTE(COUNT) \ +{ int n = (COUNT); \ + DECL_LOCALVARIABLES_OFFSET (current_method) = JCF_TELL (jcf) - 2; \ + JCF_SKIP (jcf, n * 10); } + +#define HANDLE_LINENUMBERTABLE_ATTRIBUTE(COUNT) \ +{ int n = (COUNT); \ + DECL_LINENUMBERS_OFFSET (current_method) = JCF_TELL (jcf) - 2; \ + JCF_SKIP (jcf, n * 4); } + +#include "jcf-reader.c" + +static int yydebug; + +tree +parse_signature (jcf, sig_index) + JCF *jcf; + int sig_index; +{ + if (sig_index <= 0 || sig_index >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, sig_index) != CONSTANT_Utf8) + fatal ("invalid field/method signature"); + else + { + return parse_signature_string (JPOOL_UTF_DATA (jcf, sig_index), + JPOOL_UTF_LENGTH (jcf, sig_index)); + } +} + +void +init_lex () +{ + /* Make identifier nodes long enough for the language-specific slots. */ + set_identifier_size (sizeof (struct lang_identifier)); +} + +void +set_yydebug (value) + int value; +{ + yydebug = value; +} + +tree +get_constant (jcf, index) + JCF *jcf; + int index; +{ + tree value; + int tag; + if (index <= 0 || index >= JPOOL_SIZE(jcf)) + goto bad; + tag = JPOOL_TAG (jcf, index); + if ((tag & CONSTANT_ResolvedFlag) || tag == CONSTANT_Utf8) + return (tree) jcf->cpool.data[index]; + push_obstacks (&permanent_obstack, &permanent_obstack); + switch (tag) + { + case CONSTANT_Integer: + { + jint num = JPOOL_INT(jcf, index); + value = build_int_2 (num, num < 0 ? -1 : 0); + TREE_TYPE (value) = int_type_node; + break; + } + case CONSTANT_Long: + { + jint num = JPOOL_INT (jcf, index); + HOST_WIDE_INT lo, hi; + lshift_double (num, 0, 32, 64, &lo, &hi, 0); + num = JPOOL_INT (jcf, index+1); + add_double (lo, hi, num, 0, &lo, &hi); + value = build_int_2 (lo, hi); + TREE_TYPE (value) = long_type_node; + force_fit_type (value, 0); + break; + } +#if TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT + case CONSTANT_Float: + { + jint num = JPOOL_INT(jcf, index); + REAL_VALUE_TYPE d; +#ifdef REAL_ARITHMETIC + d = REAL_VALUE_FROM_TARGET_SINGLE (num); +#else + union { float f; jint i; } u; + u.i = num; + d = u.f; +#endif + value = build_real (float_type_node, d); + break; + } + case CONSTANT_Double: + { + HOST_WIDE_INT num[2]; + REAL_VALUE_TYPE d; + HOST_WIDE_INT lo, hi; + num[0] = JPOOL_INT (jcf, index); + lshift_double (num[0], 0, 32, 64, &lo, &hi, 0); + num[0] = JPOOL_INT (jcf, index+1); + add_double (lo, hi, num[0], 0, &lo, &hi); + if (FLOAT_WORDS_BIG_ENDIAN) + { + num[0] = hi; + num[1] = lo; + } + else + { + num[0] = lo; + num[1] = hi; + } +#ifdef REAL_ARITHMETIC + d = REAL_VALUE_FROM_TARGET_DOUBLE (num); +#else + union { double d; jint i[2]; } u; + u.i[0] = (jint) num[0]; + u.i[1] = (jint) num[1]; + d = u.d; +#endif + value = build_real (double_type_node, d); + break; + } +#endif /* TARGET_FLOAT_FORMAT == IEEE_FLOAT_FORMAT */ + case CONSTANT_String: + { + extern struct obstack *expression_obstack; + tree name = get_name_constant (jcf, JPOOL_USHORT1 (jcf, index)); + char *utf8_ptr = IDENTIFIER_POINTER (name); + unsigned char *str_ptr; + int utf8_len = IDENTIFIER_LENGTH (name); + unsigned char *str = (unsigned char*)utf8_ptr; + int i = utf8_len; + int str_len; + + /* Count the number of Unicode characters in the string, + while checking for a malformed Utf8 string. */ + for (str_len = 0; i > 0; str_len++) + { + int char_len = UT8_CHAR_LENGTH (*str); + if (char_len < 0 || char_len > 2 || char_len > i) + fatal ("bad string constant"); + str += char_len; + i -= char_len; + } + + value = make_node (STRING_CST); + TREE_STRING_LENGTH (value) = 2 * str_len; + TREE_STRING_POINTER (value) + = obstack_alloc (expression_obstack, 2 * str_len); + str_ptr = (unsigned char *) TREE_STRING_POINTER (value); + str = (unsigned char*)utf8_ptr; + for (i = 0; i < str_len; i++) + { + int char_value; + int char_len = UT8_CHAR_LENGTH (*str); + switch (char_len) + { + case 1: + char_value = *str++; + break; + case 2: + char_value = *str++ & 0x1F; + char_value = (char_value << 6) | (*str++ & 0x3F); + break; + case 3: + char_value = *str_ptr++ & 0x0F; + char_value = (char_value << 6) | (*str++ & 0x3F); + char_value = (char_value << 6) | (*str++ & 0x3F); + break; + default: + goto bad; + } + if (BYTES_BIG_ENDIAN) + { + *str_ptr++ = char_value >> 8; + *str_ptr++ = char_value & 0xFF; + } + else + { + *str_ptr++ = char_value & 0xFF; + *str_ptr++ = char_value >> 8; + } + } + } + break; + default: + goto bad; + } + pop_obstacks (); + JPOOL_TAG(jcf, index) = tag | CONSTANT_ResolvedFlag; + jcf->cpool.data [index] = (jword) value; + return value; + bad: + fatal ("bad value constant type %d, index %d", + JPOOL_TAG( jcf, index ), index); +} + +tree +get_name_constant (jcf, index) + JCF *jcf; + int index; +{ + tree name = get_constant (jcf, index); + if (TREE_CODE (name) != IDENTIFIER_NODE) + fatal ("bad nameandtype index %d", index); + return name; +} + +static tree +give_name_to_class (jcf, i) + JCF *jcf; + int i; +{ + if (i <= 0 || i >= JPOOL_SIZE(jcf) + || JPOOL_TAG (jcf, i) != CONSTANT_Class) + fatal ("bad class index %d", i); + else + { + tree this_class; + int j = JPOOL_USHORT1 (jcf, i); + /* verify_constant_pool confirmed that j is a CONSTANT_Utf8. */ + tree class_name = unmangle_classname (JPOOL_UTF_DATA (jcf, j), + JPOOL_UTF_LENGTH (jcf, j)); + this_class = lookup_class (class_name); + input_filename = DECL_SOURCE_FILE (TYPE_NAME (this_class)); + lineno = 0; + if (main_input_filename == NULL && jcf == main_jcf) + main_input_filename = input_filename; + + jcf->cpool.data[i] = (jword) this_class; + JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; + return this_class; + } +} + +/* Get the class of the CONSTANT_Class whose constant pool index is I. */ + +tree +get_class_constant (JCF *jcf , int i) +{ + tree type; + if (i <= 0 || i >= JPOOL_SIZE(jcf) + || (JPOOL_TAG (jcf, i) & ~CONSTANT_ResolvedFlag) != CONSTANT_Class) + fatal ("bad class index %d", i); + + if (JPOOL_TAG (jcf, i) != CONSTANT_ResolvedClass) + { + int name_index = JPOOL_USHORT1 (jcf, i); + /* verify_constant_pool confirmed that name_index is a CONSTANT_Utf8. */ + char *name = JPOOL_UTF_DATA (jcf, name_index); + int nlength = JPOOL_UTF_LENGTH (jcf, name_index); + if (name[0] == '[') /* Handle array "classes". */ + type = parse_signature_string (name, nlength); + else + { + tree cname = unmangle_classname (name, nlength); + type = lookup_class (cname); + } + jcf->cpool.data[i] = (jword) type; + JPOOL_TAG (jcf, i) = CONSTANT_ResolvedClass; + } + else + type = (tree) jcf->cpool.data[i]; + return type; +} + +void +fix_classpath () +{ + static char default_path[] = DEFAULT_CLASS_PATH; + + if (classpath == NULL) + { + classpath = (char *) getenv ("CLASSPATH"); + if (classpath == NULL) + { + warning ("CLASSPATH not set"); + classpath = default_path; + } + } +} + +void +DEFUN(jcf_out_of_synch, (jcf), + JCF *jcf) +{ + char *source = strdup (jcf->filename); + int i = strlen (source); + + while (source[i] != '.') + i--; + + source [i] = '\0'; + warning ("Class file `%s' out of synch with `%s.java'", + jcf->filename, source); + free (source); +} + +/* Load CLASS_OR_NAME. CLASS_OR_NAME can be a mere identifier if + called from the parser, otherwise it's a RECORD_TYPE node. If + VERBOSE is 1, print error message on failure to load a class. */ + +void +load_class (class_or_name, verbose) + tree class_or_name; + int verbose; +{ + JCF this_jcf, *jcf; + tree name = (TREE_CODE (class_or_name) == IDENTIFIER_NODE ? + class_or_name : DECL_NAME (TYPE_NAME (class_or_name))); + tree save_current_class = current_class; + char *save_input_filename = input_filename; + JCF *save_current_jcf = current_jcf; + long saved_pos; + if (current_jcf->read_state) + saved_pos = ftell (current_jcf->read_state); + + push_obstacks (&permanent_obstack, &permanent_obstack); + + if (!classpath) + fix_classpath (); + /* Search in current zip first. */ + if (find_in_current_zip (IDENTIFIER_POINTER (name), + IDENTIFIER_LENGTH (name), &jcf) == 0) + if (find_class (IDENTIFIER_POINTER (name), IDENTIFIER_LENGTH (name), + &this_jcf, 1) == 0) + { + if (verbose) + { + error ("Cannot find class file class %s.", + IDENTIFIER_POINTER (name)); + TYPE_SIZE (class_or_name) = error_mark_node; + if (!strcmp (classpath, DEFAULT_CLASS_PATH)) + fatal ("giving up"); + pop_obstacks (); /* FIXME: one pop_obstack() per function */ + } + return; + } + else + { + this_jcf.seen_in_zip = 0; + current_jcf = &this_jcf; + if (this_jcf.outofsynch) + jcf_out_of_synch (current_jcf); + } + else + current_jcf = jcf; + + if (current_jcf->java_source) + jcf_parse_source (current_jcf); + else { + int saved_lineno = lineno; + input_filename = current_jcf->filename; + jcf_parse (current_jcf); + lineno = saved_lineno; + } + + if (!current_jcf->seen_in_zip) + JCF_FINISH (current_jcf); +/* DECL_IGNORED_P (TYPE_NAME (class_or_name)) = 1;*/ + pop_obstacks (); + + current_class = save_current_class; + input_filename = save_input_filename; + current_jcf = save_current_jcf; + if (current_jcf->read_state) + fseek (current_jcf->read_state, saved_pos, SEEK_SET); +} + +/* Parse a source file when JCF refers to a source file. This piece + needs further work as far as error handling and report. */ + +int +jcf_parse_source (jcf) + JCF *jcf; +{ + java_parser_context_save_global (); + + input_filename = current_jcf->filename; + if (!(finput = fopen (input_filename, "r"))) + fatal ("input file `%s' just disappeared - jcf_parse_source", + input_filename); + + parse_source_file (1); /* Parse only */ + if (current_class && TREE_TYPE (current_class)) + CLASS_FROM_SOURCE_P (TREE_TYPE (current_class)) = 1; + + fclose (finput); + java_parser_context_restore_global (); +} + +/* Parse the .class file JCF. */ + +int +jcf_parse (jcf) + JCF* jcf; +{ + int i, code; + + if (jcf_parse_preamble (jcf) != 0) + fatal ("Not a valid Java .class file.\n"); + code = jcf_parse_constant_pool (jcf); + if (code != 0) + fatal ("error while parsing constant pool"); + code = verify_constant_pool (jcf); + if (code > 0) + fatal ("error in constant pool entry #%d\n", code); + + jcf_parse_class (jcf); + if (main_class == NULL_TREE) + main_class = current_class; + if (! quiet_flag && TYPE_NAME (current_class)) + fprintf (stderr, " class %s", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)))); + CLASS_LOADED_P (current_class) = 1; + + for (i = 1; i < JPOOL_SIZE(jcf); i++) + { + switch (JPOOL_TAG (jcf, i)) + { + case CONSTANT_Class: + get_class_constant (jcf, i); + break; + } + } + + code = jcf_parse_fields (jcf); + if (code != 0) + fatal ("error while parsing fields"); + code = jcf_parse_methods (jcf); + if (code != 0) + fatal ("error while parsing methods"); + code = jcf_parse_final_attributes (jcf); + if (code != 0) + fatal ("error while parsing final attributes"); + + /* The fields of class_type_node are already in correct order. */ + if (current_class != class_type_node && current_class != object_type_node) + TYPE_FIELDS (current_class) = nreverse (TYPE_FIELDS (current_class)); + + push_obstacks (&permanent_obstack, &permanent_obstack); + layout_class (current_class); + pop_obstacks (); +} + +void +init_outgoing_cpool () +{ + current_constant_pool_data_ref = NULL_TREE; + if (outgoing_cpool == NULL) + { + static CPool outgoing_cpool_buffer; + outgoing_cpool = &outgoing_cpool_buffer; + CPOOL_INIT(outgoing_cpool); + } + else + { + CPOOL_REINIT(outgoing_cpool); + } +} + +void +parse_class_file () +{ + tree method; + char *save_input_filename = input_filename; + int save_lineno = lineno; + + input_filename = DECL_SOURCE_FILE (TYPE_NAME (current_class)); + lineno = 0; + debug_start_source_file (input_filename); + init_outgoing_cpool (); + + for ( method = TYPE_METHODS (CLASS_TO_HANDLE_TYPE (current_class)); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + JCF *jcf = current_jcf; + + if (METHOD_NATIVE (method) || METHOD_ABSTRACT (method)) + continue; + + if (DECL_CODE_OFFSET (method) == 0) + { + error ("missing Code attribute"); + continue; + } + + lineno = 0; + if (DECL_LINENUMBERS_OFFSET (method)) + { + register int i; + register unsigned char *ptr; + JCF_SEEK (jcf, DECL_LINENUMBERS_OFFSET (method)); + linenumber_count = i = JCF_readu2 (jcf); + linenumber_table = ptr = jcf->read_ptr; + + for (ptr += 2; --i >= 0; ptr += 4) + { + int line = GET_u2 (ptr); + /* Set initial lineno lineno to smallest linenumber. + * Needs to be set before init_function_start. */ + if (lineno == 0 || line < lineno) + lineno = line; + } + } + else + { + linenumber_table = NULL; + linenumber_count = 0; + } + + start_java_method (method); + + give_name_to_locals (jcf); + + /* Actually generate code. */ + expand_byte_code (jcf, method); + + end_java_method (); + } + + if (flag_emit_class_files) + write_classfile (current_class); + make_class_data (current_class); + register_class (); + rest_of_decl_compilation (TYPE_NAME (current_class), (char*) 0, 1, 0); + + debug_end_source_file (save_lineno); + input_filename = save_input_filename; + lineno = save_lineno; +} + +/* Parse a source file, as pointed by the current JCF. If PARSE_ONLY + is non zero, we're not parsing a file found on the command line and + we skip things related to code generation. */ + +static void +parse_source_file (parse_only) + int parse_only; +{ + lang_init_source (1); /* Error msgs have no method prototypes */ + java_push_parser_context (); + java_init_lex (); /* Initialize the parser */ + java_parse_abort_on_error (); + java_parse (); /* Parse and build partial tree nodes. */ + java_parse_abort_on_error (); + java_complete_class (); /* Parse unsatisfied class decl. */ + java_parse_abort_on_error (); + java_check_circular_reference (); /* Check on circular references */ + java_parse_abort_on_error (); + java_check_methods (); /* Check the methods */ + java_parse_abort_on_error (); + java_layout_classes (); + java_parse_abort_on_error (); + if (!parse_only) + { + lang_init_source (2); /* Error msgs have method prototypes */ + java_complete_expand_methods (); /* Complete and expand method bodies */ + java_parse_abort_on_error (); + java_expand_finals (); /* Expand and check the finals */ + java_parse_abort_on_error (); + java_check_final (); /* Check unitialized final */ + java_parse_abort_on_error (); + if (! flag_emit_class_files) + emit_register_class (); + java_report_errors (); /* Final step for this file */ + } + if (flag_emit_class_files) + write_classfile (current_class); + java_pop_parser_context (); +} + +int +yyparse () +{ + /* Everything migh be enclosed within a loop processing each file after + the other one. */ + + switch (jcf_figure_file_type (current_jcf)) + { + case JCF_ZIP: + parse_zip_file_entries (); + emit_register_class (); + break; + case JCF_CLASS: + jcf_parse (current_jcf); + parse_class_file (); + emit_register_class (); + break; + case JCF_SOURCE: + parse_source_file (0); /* Parse and generate */ + break; + } + return 0; +} + +static struct ZipFileCache *localToFile; + +/* Process all class entries found in the zip file. */ +void +parse_zip_file_entries (void) +{ + struct ZipDirectory *zdir; + int i; + + for (i = 0, zdir = (ZipDirectory *)localToFile->z.central_directory; + i < localToFile->z.count; i++, zdir = ZIPDIR_NEXT (zdir)) + { + tree class; + + /* We don't need to consider those files. */ + if (!zdir->size || !zdir->filename_offset) + continue; + + class = lookup_class (get_identifier (ZIPDIR_FILENAME (zdir))); + current_jcf = TYPE_LANG_SPECIFIC (class)->jcf; + current_class = class; + + if ( !CLASS_LOADED_P (class)) + { + fseek (current_jcf->read_state, current_jcf->zip_offset, SEEK_SET); + jcf_parse (current_jcf); + } + + input_filename = current_jcf->filename; + + parse_class_file (); + FREE (current_jcf->buffer); /* No longer necessary */ + /* Note: there is a way to free this buffer right after a class seen + in a zip file has been parsed. The idea is the set its jcf in such + a way that buffer will be reallocated the time the code for the class + will be generated. FIXME. */ + } +} + +/* Read all the entries of the zip file, creates a class and a JCF. Sets the + jcf up for further processing and link it to the created class. */ + +void process_zip_dir() +{ + int i; + ZipDirectory *zdir; + + for (i = 0, zdir = (ZipDirectory *)localToFile->z.central_directory; + i < localToFile->z.count; i++, zdir = ZIPDIR_NEXT (zdir)) + { + char *class_name, *file_name, *class_name_in_zip_dir; + tree class; + JCF *jcf; + int j; + + class_name_in_zip_dir = ZIPDIR_FILENAME (zdir); + + /* We choose to not to process entries with a zero size or entries + not bearing the .class extention. */ + if (!zdir->size || !zdir->filename_offset || + strncmp (&class_name_in_zip_dir[zdir->filename_length-6], + ".class", 6)) + { + /* So it will be skipped in parse_zip_file_entries */ + zdir->size = 0; + continue; + } + + class_name = ALLOC (zdir->filename_length+1-6); + file_name = ALLOC (zdir->filename_length+1); + jcf = ALLOC (sizeof (JCF)); + JCF_ZERO (jcf); + + strncpy (class_name, class_name_in_zip_dir, zdir->filename_length-6); + class_name [zdir->filename_length-6] = '\0'; + strncpy (file_name, class_name_in_zip_dir, zdir->filename_length); + file_name [zdir->filename_length] = '\0'; + + for (j=0; class_name[j]; j++) + class_name [j] = (class_name [j] == '/' ? '.' : class_name [j]); + + /* Yes, we write back the true class name into the zip directory. */ + strcpy (class_name_in_zip_dir, class_name); + zdir->filename_length = j; + class = lookup_class (get_identifier (class_name)); + + jcf->read_state = finput; + jcf->filbuf = jcf_filbuf_from_stdio; + jcf->seen_in_zip = 1; + jcf->java_source = 0; + jcf->zip_offset = zdir->filestart; + jcf->classname = class_name; + jcf->filename = file_name; + + TYPE_LANG_SPECIFIC (class) = + (struct lang_type *) perm_calloc (1, sizeof (struct lang_type)); + TYPE_LANG_SPECIFIC (class)->jcf = jcf; + } +} + +/* Lookup class NAME and figure whether is a class already found in the current + zip file. */ +int +DEFUN(find_in_current_zip, (name, length, jcf), + char *name AND int length AND JCF **jcf) +{ + JCF *local_jcf; + tree class_name = maybe_get_identifier (name), class, icv; + + if (!class_name) + return 0; + + if (!(icv = IDENTIFIER_CLASS_VALUE (class_name))) + return 0; + + class = TREE_TYPE (icv); + + /* Doesn't have jcf specific info ? It's not ours */ + if (!TYPE_LANG_SPECIFIC (class) || !TYPE_LANG_SPECIFIC (class)->jcf) + return 0; + + *jcf = local_jcf = TYPE_LANG_SPECIFIC (class)->jcf; + fseek (local_jcf->read_state, local_jcf->zip_offset, SEEK_SET); + return 1; +} + +/* Figure what kind of file we're dealing with */ +int +DEFUN(jcf_figure_file_type, (jcf), + JCF *jcf) +{ + unsigned char magic_string[4]; + uint32 magic; + + if (fread (magic_string, 1, 4, jcf->read_state) != 4) + jcf_unexpected_eof (jcf, 4); + + fseek (jcf->read_state, 0L, SEEK_SET); + magic = GET_u4 (magic_string); + + if (magic == 0xcafebabe) + return JCF_CLASS; + + if (!open_in_zip (jcf, input_filename, NULL)) + { + localToFile = ALLOC (sizeof (struct ZipFileCache)); + bcopy (SeenZipFiles, localToFile, sizeof (struct ZipFileCache)); + process_zip_dir (); /* Register all the class defined there */ + return JCF_ZIP; + } + + return JCF_SOURCE; +} + diff --git a/gcc/java/jcf-reader.c b/gcc/java/jcf-reader.c new file mode 100644 index 00000000000..cf5c0427789 --- /dev/null +++ b/gcc/java/jcf-reader.c @@ -0,0 +1,352 @@ +/* This file read a Java(TM) .class file. + It is not stand-alone: It depends on tons of macros, and the + intent is you #include this file after you've defined the macros. + + Copyright (C) 1996 Free Software Foundation, Inc. + +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, 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 GNU CC; 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. */ + +#include "jcf.h" +#include "zipfile.h" + +int +DEFUN(get_attribute, (jcf), + JCF *jcf) +{ + uint16 attribute_name = (JCF_FILL (jcf, 6), JCF_readu2 (jcf)); + uint32 attribute_length = JCF_readu4 (jcf); + uint32 start_pos = JCF_TELL(jcf); + int name_length; + unsigned char *name_data; + JCF_FILL (jcf, attribute_length); + if (attribute_name <= 0 || attribute_name >= JPOOL_SIZE(jcf)) + return -2; + if (JPOOL_TAG (jcf, attribute_name) != CONSTANT_Utf8) + return -2; + name_length = JPOOL_UTF_LENGTH (jcf, attribute_name); + name_data = JPOOL_UTF_DATA (jcf, attribute_name); + +#ifdef IGNORE_ATTRIBUTE + if (IGNORE_ATTRIBUTE (jcf, attribute_name, attribute_length)) + { + JCF_SKIP (jcf, attribute_length); + } + else +#endif +#ifdef HANDLE_SOURCEFILE + if (name_length == 10 && memcmp (name_data, "SourceFile", 10) == 0) + { + uint16 sourcefile_index = JCF_readu2 (jcf); + HANDLE_SOURCEFILE(sourcefile_index); + } + else +#endif +#ifdef HANDLE_CONSTANTVALUE + if (name_length == 13 && memcmp (name_data, "ConstantValue", 13) == 0) + { + uint16 constantvalue_index = JCF_readu2 (jcf); + if (constantvalue_index <= 0 || constantvalue_index >= JPOOL_SIZE(jcf)) + return -2; + HANDLE_CONSTANTVALUE(constantvalue_index); + } + else +#endif +#ifdef HANDLE_CODE_ATTRIBUTE + if (name_length == 4 && memcmp (name_data, "Code", 4) == 0) + { + uint16 j; + uint16 max_stack = JCF_readu2 (jcf); + uint16 max_locals = JCF_readu2 (jcf); + uint32 code_length = JCF_readu4 (jcf); + uint16 exception_table_length, attributes_count; + if (code_length + 12 > attribute_length) + return -1; + HANDLE_CODE_ATTRIBUTE(max_stack, max_locals, code_length); + JCF_SKIP (jcf, code_length); + exception_table_length = JCF_readu2 (jcf); + if (code_length + 8 * exception_table_length + 12 > attribute_length) + return -1; + JCF_SKIP (jcf, 2 * 4 * exception_table_length); + attributes_count = JCF_readu2 (jcf); + for (j = 0; j < attributes_count; j++) + { + int code = get_attribute (jcf); + if (code != 0) + return code; + } + } + else +#endif /* HANDLE_CODE_ATTRIBUTE */ +#ifdef HANDLE_EXCEPTIONS_ATTRIBUTE + if (name_length == 10 && memcmp (name_data, "Exceptions", 10) == 0) + { + uint16 count = JCF_readu2 (jcf); + HANDLE_EXCEPTIONS_ATTRIBUTE (count); + } + else +#endif +#ifdef HANDLE_LINENUMBERTABLE_ATTRIBUTE + if (name_length == 15 && memcmp (name_data, "LineNumberTable", 15) == 0) + { + uint16 count = JCF_readu2 (jcf); + HANDLE_LINENUMBERTABLE_ATTRIBUTE (count); + } + else +#endif +#ifdef HANDLE_LOCALVARIABLETABLE_ATTRIBUTE + if (name_length == 18 && memcmp (name_data, "LocalVariableTable", 18) == 0) + { + uint16 count = JCF_readu2 (jcf); + HANDLE_LOCALVARIABLETABLE_ATTRIBUTE (count); + } + else +#endif + { +#ifdef PROCESS_OTHER_ATTRIBUTE + PROCESS_OTHER_ATTRIBUTE(jcf, attribute_name, attribute_length); +#else + JCF_SKIP (jcf, attribute_length); +#endif + } + if (start_pos + attribute_length != JCF_TELL(jcf)) + return -1; + return 0; +} + +/* Read and handle the pre-amble. */ +int +DEFUN(jcf_parse_preamble, (jcf), + JCF* jcf) +{ + uint32 magic = (JCF_FILL (jcf, 8), JCF_readu4 (jcf)); + uint16 minor_version = JCF_readu2 (jcf); + uint16 major_version = JCF_readu2 (jcf); +#ifdef HANDLE_MAGIC + HANDLE_MAGIC (magic, minor_version, major_version); +#endif + if (magic != 0xcafebabe) + return -1; + else + return 0; +} + +/* Read and handle the constant pool. + + Return 0 if OK. + Return -2 if a bad cross-reference (index of other constant) was seen. +*/ +int +DEFUN(jcf_parse_constant_pool, (jcf), + JCF* jcf) +{ + int i, n; + JPOOL_SIZE (jcf) = (JCF_FILL (jcf, 2), JCF_readu2 (jcf)); + jcf->cpool.tags = ALLOC (JPOOL_SIZE (jcf)); + jcf->cpool.data = ALLOC (sizeof (jword) * JPOOL_SIZE (jcf)); + jcf->cpool.tags[0] = 0; +#ifdef HANDLE_START_CONSTANT_POOL + HANDLE_START_CONSTANT_POOL (JPOOL_SIZE (jcf)); +#endif + for (i = 1; i < (int) JPOOL_SIZE (jcf); i++) + { + int constant_kind; + + /* Make sure at least 9 bytes are available. This is enough + for all fixed-sized constant pool entries (so we don't need many + more JCF_FILL calls below), but is is small enough that + we are guaranteed to not hit EOF (in a valid .class file). */ + JCF_FILL (jcf, 9); + constant_kind = JCF_readu (jcf); + jcf->cpool.tags[i] = constant_kind; + switch (constant_kind) + { + case CONSTANT_String: + case CONSTANT_Class: + jcf->cpool.data[i] = JCF_readu2 (jcf); + break; + case CONSTANT_Fieldref: + case CONSTANT_Methodref: + case CONSTANT_InterfaceMethodref: + case CONSTANT_NameAndType: + jcf->cpool.data[i] = JCF_readu2 (jcf); + jcf->cpool.data[i] |= JCF_readu2 (jcf) << 16; + break; + case CONSTANT_Integer: + case CONSTANT_Float: + jcf->cpool.data[i] = JCF_readu4 (jcf); + break; + case CONSTANT_Long: + case CONSTANT_Double: + jcf->cpool.data[i] = JCF_readu4 (jcf); + i++; /* These take up two spots in the constant pool */ + jcf->cpool.tags[i] = 0; + jcf->cpool.data[i] = JCF_readu4 (jcf); + break; + case CONSTANT_Utf8: + n = JCF_readu2 (jcf); + JCF_FILL (jcf, n); +#ifdef HANDLE_CONSTANT_Utf8 + HANDLE_CONSTANT_Utf8(jcf, i, n); +#else + jcf->cpool.data[i] = JCF_TELL(jcf) - 2; + JCF_SKIP (jcf, n); +#endif + break; + default: + return i; + } + } + return 0; +} + +/* Read various class flags and numbers. */ + +void +DEFUN(jcf_parse_class, (jcf), + JCF* jcf) +{ + int i; + uint16 interfaces_count; + JCF_FILL (jcf, 8); + jcf->access_flags = JCF_readu2 (jcf); + jcf->this_class = JCF_readu2 (jcf); + jcf->super_class = JCF_readu2 (jcf); + interfaces_count = JCF_readu2 (jcf); + +#ifdef HANDLE_CLASS_INFO + HANDLE_CLASS_INFO(jcf->access_flags, jcf->this_class, jcf->super_class, interfaces_count); +#endif + + JCF_FILL (jcf, 2 * interfaces_count); + + /* Read interfaces. */ + for (i = 0; i < interfaces_count; i++) + { + uint16 index = JCF_readu2 (jcf); +#ifdef HANDLE_CLASS_INTERFACE + HANDLE_CLASS_INTERFACE (index); +#endif + } +} + +/* Read fields. */ +int +DEFUN(jcf_parse_fields, (jcf), + JCF* jcf) +{ + int i, j; + uint16 fields_count; + JCF_FILL (jcf, 2); + fields_count = JCF_readu2 (jcf); + +#ifdef HANDLE_START_FIELDS + HANDLE_START_FIELDS (fields_count); +#endif + for (i = 0; i < fields_count; i++) + { + uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf)); + uint16 name_index = JCF_readu2 (jcf); + uint16 signature_index = JCF_readu2 (jcf); + uint16 attribute_count = JCF_readu2 (jcf); +#ifdef HANDLE_START_FIELD + HANDLE_START_FIELD (access_flags, name_index, signature_index, + attribute_count); +#endif + for (j = 0; j < attribute_count; j++) + { + int code = get_attribute (jcf); + if (code != 0) + return code; + } +#ifdef HANDLE_END_FIELD + HANDLE_END_FIELD (); +#endif + } +#ifdef HANDLE_END_FIELDS + HANDLE_END_FIELDS (); +#endif + return 0; +} + +/* Read methods. */ + +int +DEFUN(jcf_parse_one_method, (jcf), + JCF* jcf) +{ + int i; + uint16 access_flags = (JCF_FILL (jcf, 8), JCF_readu2 (jcf)); + uint16 name_index = JCF_readu2 (jcf); + uint16 signature_index = JCF_readu2 (jcf); + uint16 attribute_count = JCF_readu2 (jcf); +#ifdef HANDLE_METHOD + HANDLE_METHOD(access_flags, name_index, signature_index, attribute_count); +#endif + for (i = 0; i < attribute_count; i++) + { + int code = get_attribute (jcf); + if (code != 0) + return code; + } + return 0; +} + +int +DEFUN(jcf_parse_methods, (jcf), + JCF* jcf) +{ + int i; + uint16 methods_count; + JCF_FILL (jcf, 2); + methods_count = JCF_readu2 (jcf); +#ifdef HANDLE_START_METHODS + HANDLE_START_METHODS (methods_count); +#endif + for (i = 0; i < methods_count; i++) + { + int code = jcf_parse_one_method (jcf); + if (code != 0) + return code; + } +#ifdef HANDLE_END_METHODS + HANDLE_END_METHODS (); +#endif + return 0; +} + +/* Read attributes. */ +int +DEFUN(jcf_parse_final_attributes, (jcf), + JCF *jcf) +{ + int i; + uint16 attributes_count = (JCF_FILL (jcf, 2), JCF_readu2 (jcf)); +#ifdef START_FINAL_ATTRIBUTES + START_FINAL_ATTRIBUTES (attributes_count) +#endif + for (i = 0; i < attributes_count; i++) + { + int code = get_attribute (jcf); + if (code != 0) + return code; + } + return 0; +} + diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c new file mode 100644 index 00000000000..931c9d582c1 --- /dev/null +++ b/gcc/java/jcf-write.c @@ -0,0 +1,964 @@ +/* Write out a Java(TM) class file. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +#include "config.h" +#include "tree.h" +#include "java-tree.h" +#include "jcf.h" +#include +#include "obstack.h" +#undef AND +#include "rtl.h" +#include "java-opcodes.h" +#include "parse.h" /* for BLOCK_EXPR_BODY */ +#include "buffer.h" + +extern struct obstack temporary_obstack; + +/* The buffer allocated for bytecode for the current method. */ + +struct buffer bytecode = NULL_BUFFER; + +/* Make sure bytecode.data is big enough for at least N more bytes. */ + +#define RESERVE(N) \ + do { if (bytecode.ptr + (N) > bytecode.limit) buffer_grow (&bytecode, N); } while (0) + +/* Add a 1-byte instruction/operand I to bytecode.data, + assuming space has already been RESERVE'd. */ + +#define OP1(I) (*bytecode.ptr++ = (I)) + +/* Like OP1, but I is a 2-byte big endian integer. */ + +#define OP2(I) \ + do { int _I = (I); OP1 (_I >> 8); OP1 (_I); } while (0) + +/* Like OP1, but I is a 4-byte big endian integer. */ + +#define OP4(I) \ + do { int _I = (I); OP1 (_I >> 24); OP1 (_I >> 16); \ + OP1 (_I >> 8); OP1 (_I); } while (0) + +/* The current stack size (stack pointer) in the current method. */ + +int code_SP = 0; + +/* The largest extent of stack size (stack pointer) in the current method. */ + +int code_SP_max = 0; + +CPool *code_cpool; + +/* Macro to call each time we push I words on the JVM stack. */ + +#define NOTE_PUSH(I) \ + do { code_SP += (I); if (code_SP > code_SP_max) code_SP_max = code_SP; } while (0) + +/* Macro to call each time we pop I words from the JVM stack. */ + +#define NOTE_POP(I) \ + do { code_SP -= (I); if (code_SP < 0) abort(); } while (0) + +/* A chunk or segment of a .class file. */ + +struct chunk +{ + /* The next segment of this .class file. */ + struct chunk *next; + + /* The actual data in this segment to be written to the .class file. */ + unsigned char *data; + + /* The size of the segment to be written to the .class file. */ + int size; +}; + +/* Utility macros for appending (big-endian) data to a buffer. + We assume a local variable 'ptr' points into where we want to + write next, and we assume enoygh space has been allocated. */ + +#define PUT1(X) (*ptr++ = (X)) +#define PUT2(X) (PUT1((X) >> 8), PUT1((X) & 0xFF)) +#define PUT4(X) (PUT2((X) >> 16), PUT2((X) & 0xFFFF)) +#define PUTN(P, N) (bcopy(P, ptr, N), ptr += (N)) + + +/* A buffer for storing line number entries for the current method. */ +struct buffer linenumbers = NULL_BUFFER; + +/* Append a line number entry for the given PC and LINE into + linenumbers.data. This will later before a LineNumberTable attribute. */ + +void +put_linenumber (pc, line) + int pc, line; +{ + register unsigned char *ptr; + if (linenumbers.ptr == linenumbers.limit) + buffer_grow (&linenumbers, 4); + ptr = linenumbers.ptr; + PUT2 (pc); + PUT2 (line); + linenumbers.ptr = ptr; +} + +/* The index of jvm local variable allocated for this DECL. + This is assign when generating .class files; + contrast DECL_LOCAL_SLOT_NUMBER whcih is set when *reading* a .class file. + (We don't allocate DECL_LANG_SPECIFIC for locals from Java sourc code.) */ + +#define DECL_LOCAL_INDEX(DECL) DECL_ALIGN(DECL) + +struct localvar_info +{ + tree decl; + + int start_pc; + + /* Offset in LocalVariableTable. */ + int debug_offset; +}; + +struct buffer localvars = NULL_BUFFER; + +#define localvar_buffer ((struct localvar_info*) localvars.data) +#define localvar_max ((struct localvar_info*) localvars.ptr - localvar_buffer) + +/* A buffer for storing LocalVariableTable entries entries. */ + +struct buffer localvartable = NULL_BUFFER; + +int +localvar_alloc (decl, start_pc) + tree decl; + int start_pc; +{ + int wide = TYPE_IS_WIDE (TREE_TYPE (decl)); + int index; + register struct localvar_info *info = (struct localvar_info*)localvars.data; + register struct localvar_info *limit = (struct localvar_info*)localvars.ptr; + for (index = 0; info < limit; index++, info++) + { + if (info->decl == NULL_TREE + && (! wide || (info+1)->decl == NULL_TREE)) + break; + } + if (info == limit) + { + buffer_grow (&localvars, sizeof (struct localvar_info)); + info = (struct localvar_info*)localvars.data + index; + localvars.ptr = (unsigned char *) (info + 1 + wide); + } + info->decl = decl; + if (wide) + (info+1)->decl = TYPE_SECOND; + DECL_LOCAL_INDEX (decl) = index; + info->start_pc = start_pc; + + if (DECL_NAME (decl) != NULL_TREE) + { + /* Generate debugging info. */ + int i; + register unsigned char *ptr; + buffer_grow (&localvartable, 10); + ptr = localvartable.ptr; + info->debug_offset = ptr - localvartable.data; + PUT2 (start_pc); + PUT2 (0); /* length - fill in later */ + i = find_utf8_constant (code_cpool, DECL_NAME (decl)); + PUT2 (i); /* name_index*/ + i = find_utf8_constant (code_cpool, + build_java_signature (TREE_TYPE (decl))); + PUT2 (i); /* descriptor_index */ + PUT2 (index); + localvartable.ptr = ptr; + } + else + info->debug_offset = -1; +} + +int +localvar_free (decl, end_pc) + tree decl; + int end_pc; +{ + register unsigned char *ptr; + int index = DECL_LOCAL_INDEX (decl); + register struct localvar_info *info = &localvar_buffer [index]; + int wide = TYPE_IS_WIDE (TREE_TYPE (decl)); + int i; + + i = info->debug_offset; + if (i >= 0) + { + register unsigned char *ptr; + /* Point to length field of local_variable_table. */ + ptr = localvartable.data + i + 2; + i = end_pc - info->start_pc; + PUT2 (i); + } + + if (info->decl != decl) + abort (); + info->decl = NULL_TREE; + if (wide) + { + info++; + if (info->decl != TYPE_SECOND) + abort (); + info->decl = NULL_TREE; + } + +} + + +#define STACK_TARGET 1 +#define IGNORE_TARGET 2 + +/* Allocate a new chunk on obstack WORK, and link it in after LAST. + Set the data and size fields to DATA and SIZE, respectively. + However, if DATA is NULL and SIZE>0, allocate a buffer as well. */ + +struct chunk * +alloc_chunk (last, data, size, work) + struct chunk *last; + unsigned char *data; + int size; + struct obstack *work; +{ + struct chunk *chunk = (struct chunk *) + obstack_alloc (work, sizeof(struct chunk)); + + if (data == NULL && size > 0) + data = obstack_alloc (work, size); + + chunk->next = NULL; + chunk->data = data; + chunk->size = size; + last->next = chunk; + return chunk; +} + +/* Get the access flags of a class (TYPE_DECL), a method (FUNCTION_DECL), or + a field (FIELD_DECL or VAR_DECL, if static), as encoded in a .class file. */ + +int +get_access_flags (decl) + tree decl; +{ + int flags = 0; + int isfield = TREE_CODE (decl) == FIELD_DECL || TREE_CODE (decl) == VAR_DECL; + if (CLASS_PUBLIC (decl)) /* same as FIELD_PUBLIC and METHOD_PUBLIC */ + flags |= ACC_PUBLIC; + if (CLASS_FINAL (decl)) /* same as FIELD_FINAL and METHOD_FINAL */ + flags |= ACC_PUBLIC; + if (isfield || TREE_CODE (decl) == FUNCTION_DECL) + { + if (TREE_PROTECTED (decl)) + flags |= ACC_PROTECTED; + if (TREE_PRIVATE (decl)) + flags |= ACC_PRIVATE; + } + else if (TREE_CODE (decl) == TYPE_DECL) + { + if (CLASS_SUPER (decl)) + flags |= ACC_SUPER; + if (CLASS_ABSTRACT (decl)) + flags |= ACC_ABSTRACT; + if (CLASS_INTERFACE (decl)) + flags |= ACC_INTERFACE; + } + else + fatal ("internal error - bad argument to get_access_flags"); + if (TREE_CODE (decl) == FUNCTION_DECL) + { + if (METHOD_NATIVE (decl)) + flags |= ACC_NATIVE; + if (METHOD_STATIC (decl)) + flags |= ACC_STATIC; + if (METHOD_FINAL (decl)) + flags |= ACC_FINAL; + if (METHOD_SYNCHRONIZED (decl)) + flags |= ACC_SYNCHRONIZED; + if (METHOD_ABSTRACT (decl)) + flags |= ACC_ABSTRACT; + } + if (isfield) + { + if (FIELD_STATIC (decl)) + flags |= ACC_STATIC; + if (FIELD_VOLATILE (decl)) + flags |= ACC_VOLATILE; + if (FIELD_TRANSIENT (decl)) + flags |= ACC_TRANSIENT; + } + return flags; +} + +/* Write the list of segments starting at CHUNKS to STREAM. */ + +void +write_chunks (stream, chunks) + FILE* stream; + struct chunk *chunks; +{ + for (; chunks != NULL; chunks = chunks->next) + fwrite (chunks->data, chunks->size, 1, stream); +} + +void +push_constant1 (index) + int index; +{ + if (index < 256) + { + OP1 (OPCODE_ldc); + OP1 (index); + } + else + { + OP1 (OPCODE_ldc_w); + OP2 (index); + } +} + +void +push_constant2 (index) + int index; +{ + RESERVE (3); + OP1 (OPCODE_ldc2_w); + OP2 (index); +} + +void +push_int_const (i) + HOST_WIDE_INT i; +{ + RESERVE(3); + if (i >= -1 && i <= 5) + OP1(OPCODE_iconst_0 + i); + else if (i >= -128 && i < 128) + { + OP1(OPCODE_bipush); + OP1(i); + } + else if (i >= -32768 && i < 32768) + { + OP1(OPCODE_sipush); + OP2(i); + } + else + { + i = find_constant1 (code_cpool, CONSTANT_Integer, i & 0xFFFFFFFF); + push_constant1 (i); + } +} + +void +push_long_const (lo, hi) + HOST_WIDE_INT lo, hi; +{ + if (hi == 0 && lo >= 0 && lo <= 1) + { + RESERVE(1); + OP1(OPCODE_lconst_0 + lo); + } +#if 0 + else if ((jlong) (jint) i == i) + { + push_int_const ((jint) i); + RESERVE (1); + OP1 (OPCODE_i2l); + } +#endif + else + { + HOST_WIDE_INT w1, w2; + lshift_double (lo, hi, -32, 64, &w1, &w2, 1); + hi = find_constant1 (code_cpool, CONSTANT_Long, + w1 & 0xFFFFFFFF, lo & 0xFFFFFFFF); + push_constant2 (hi); + } +} + +void +field_op (field, opcode) + tree field; + int opcode; +{ + int index = find_fieldref_index (code_cpool, field); + RESERVE (3); + OP1 (opcode); + OP2 (index); +} + +/* Returns an integer in the range 0 (for 'int') through 4 (for object + reference) to 7 (for 'short') which matches the pattern of how JVM + opcodes typically depend on the operand type. */ + +int +adjust_typed_op (type) + tree type; +{ + switch (TREE_CODE (type)) + { + case BOOLEAN_TYPE: return 5; + case CHAR_TYPE: return 6; + case POINTER_TYPE: + case RECORD_TYPE: return 4; + case INTEGER_TYPE: + switch (TYPE_PRECISION (type)) + { + case 8: return 5; + case 16: return 7; + case 32: return 0; + case 64: return 1; + } + break; + case REAL_TYPE: + switch (TYPE_PRECISION (type)) + { + case 32: return 2; + case 64: return 3; + } + break; + } + abort (); +} + +void +maybe_wide (opcode, index) + int opcode, index; +{ + if (index >= 256) + { + RESERVE (4); + OP1 (196); /* wide */ + OP1 (opcode); + OP2 (index); + } + else + { + RESERVE (2); + OP1 (opcode); + OP1 (index); + } +} + +#define PC BUFFER_LENGTH(&bytecode) + +/* Generate byetcode for sub-expression EXP of METHOD. + TARGET is one of STACK_TARGET or IGNORE_TARGET. */ + +void +generate_bytecode_insns (method, exp, target) + tree method; + tree exp; + int target; +{ + rtx value; + tree type = TREE_TYPE (exp); + enum java_opcode jopcode; + int op; + switch (TREE_CODE (exp)) + { + case BLOCK: + if (BLOCK_EXPR_BODY (exp)) + { + tree local; + for (local = BLOCK_EXPR_DECLS (exp); local; ) + { + tree next = TREE_CHAIN (local); + localvar_alloc (local, PC); + local = next; + } + generate_bytecode_insns (method, BLOCK_EXPR_BODY (exp), target); + for (local = BLOCK_EXPR_DECLS (exp); local; ) + { + tree next = TREE_CHAIN (local); + localvar_free (local, PC); + local = next; + } + } + break; + case COMPOUND_EXPR: + generate_bytecode_insns (method, TREE_OPERAND (exp, 0), IGNORE_TARGET); + generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target); + break; + case EXPR_WITH_FILE_LOCATION: + { + char *saved_input_filename = input_filename; + int saved_lineno = lineno; + input_filename = EXPR_WFL_FILENAME (exp); + lineno = EXPR_WFL_LINENO (exp); + if (EXPR_WFL_EMIT_LINE_NOTE (exp)) + put_linenumber (PC, EXPR_WFL_LINENO (exp)); + generate_bytecode_insns (method, EXPR_WFL_NODE (exp), target); + input_filename = saved_input_filename; + lineno = saved_lineno; + } + break; + case INTEGER_CST: + if (target == IGNORE_TARGET) ; /* do nothing */ + else if (TREE_CODE (type) == POINTER_TYPE) + { + if (! integer_zerop (exp)) + abort(); + RESERVE(1); + OP1 (OPCODE_aconst_null); + NOTE_PUSH (1); + } + else if (TYPE_PRECISION (type) <= 32) + { + push_int_const (TREE_INT_CST_LOW (exp)); + NOTE_PUSH (1); + } + else + { + push_long_const (TREE_INT_CST_LOW (exp), TREE_INT_CST_HIGH (exp)); + NOTE_PUSH (2); + } + break; + case VAR_DECL: + if (TREE_STATIC (exp)) + { + field_op (exp, OPCODE_getstatic); + break; + } + /* ... fall through ... */ + case PARM_DECL: + { + int kind = adjust_typed_op (type); + int index = DECL_LOCAL_INDEX (exp); + if (index <= 3) + { + RESERVE (1); + OP1 (26 + 4 * kind + index); /* [ilfda]load_[0123] */ + } + else + maybe_wide (21 + kind, index); /* [ilfda]load */ + } + break; + case INDIRECT_REF: + generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target); + break; + case ARRAY_REF: + generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target); + generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target); + if (target != IGNORE_TARGET) + { + jopcode = OPCODE_iaload + adjust_typed_op (type); + RESERVE(1); + OP1 (jopcode); + } + break; + case COMPONENT_REF: + { + tree obj = TREE_OPERAND (exp, 0); + tree field = TREE_OPERAND (exp, 1); + int is_static = FIELD_STATIC (field); + generate_bytecode_insns (method, obj, + is_static ? IGNORE_TARGET : target); + if (target != IGNORE_TARGET) + { + if (DECL_NAME (field) == length_identifier_node && !is_static + && TYPE_ARRAY_P (TREE_TYPE (obj))) + { + RESERVE (1); + OP1 (OPCODE_arraylength); + } + else + field_op (field, is_static ? OPCODE_getstatic : OPCODE_getfield); + } + } + break; + case RETURN_EXPR: + if (!TREE_OPERAND (exp, 0)) + op = OPCODE_return; + else + { + exp = TREE_OPERAND (exp, 0); + if (TREE_CODE (exp) != MODIFY_EXPR) + abort (); + exp = TREE_OPERAND (exp, 1); + op = OPCODE_ireturn + adjust_typed_op (TREE_TYPE (exp)); + generate_bytecode_insns (method, exp, STACK_TARGET); + } + RESERVE (1); + OP1 (op); + break; + case MODIFY_EXPR: + { + tree lhs = TREE_OPERAND (exp, 0); + tree rhs = TREE_OPERAND (exp, 1); + HOST_WIDE_INT value; +#if 0 + if (TREE_CODE (rhs) == PLUS_EXPR + && TREE_CODE (lhs) == VAR_DECL + /* && FIXME lhs is a local variable */ + && TYPE_MODE (TREE)TYPE (lhs) == SImode /* ??? */ + && TREE_OPERAND (rhs, 0) == lhs + && TREE_CODE (TREE_OPERAND (rhs, 1)) == INTEGER_CST + /* or vice versa FIXME */ + && (value = TREE_INT_CST_LOW (TREE_OPERAND (rhs, 1)), + (value >= -32768 && value <= 32767))) + { + emit_insn (gen_rtx (SET, SImode, + DECL_RTL (lhs), + gen_rtx (PLUS, SImode, + DECL_RTL (lhs), + gen_rtx_CONST_INT (SImode, value)))); + return DECL_RTL (lhs); + } +#endif + if (TREE_CODE (lhs) == COMPONENT_REF) + generate_bytecode_insns (method, TREE_OPERAND (lhs, 0), STACK_TARGET); + else if (TREE_CODE (lhs) == ARRAY_REF) + { + generate_bytecode_insns (method, + TREE_OPERAND (lhs, 0), STACK_TARGET); + generate_bytecode_insns (method, + TREE_OPERAND (lhs, 1), STACK_TARGET); + } + generate_bytecode_insns (method, rhs, STACK_TARGET); + if (target != IGNORE_TARGET) + { + RESERVE (1); + OP1 (TYPE_IS_WIDE (type) ? OPCODE_dup2_x1 : OPCODE_dup_x1); + } + if (TREE_CODE (lhs) == COMPONENT_REF) + { + tree field = TREE_OPERAND (lhs, 1); + field_op (field, + FIELD_STATIC (field) ? OPCODE_putstatic + : OPCODE_putfield); + } + else if (TREE_CODE (lhs) == VAR_DECL + || TREE_CODE (lhs) == PARM_DECL) + { + if (FIELD_STATIC (lhs)) + { + field_op (lhs, OPCODE_putstatic); + } + else + { + int index = DECL_LOCAL_INDEX (lhs); + int opcode = adjust_typed_op (TREE_TYPE (lhs)); + if (index <= 3) + { + RESERVE (1); + opcode = 59 + 4 * opcode + index; + OP1 (opcode); /* [ilfda]store_[0123] */ + } + else + { + maybe_wide (54 + opcode, index); /* [ilfda]store */ + } + } + } + else if (TREE_CODE (lhs) == ARRAY_REF) + { + jopcode = OPCODE_iastore + adjust_typed_op (TREE_TYPE (lhs)); + RESERVE(1); + OP1 (jopcode); + } + else + fatal ("internal error (bad lhs to MODIFY_EXPR)"); + } + break; + case PLUS_EXPR: + jopcode = OPCODE_iadd + adjust_typed_op (type); + goto binop; + case MINUS_EXPR: + jopcode = OPCODE_isub + adjust_typed_op (type); + goto binop; + case MULT_EXPR: + jopcode = OPCODE_imul + adjust_typed_op (type); + goto binop; + case TRUNC_DIV_EXPR: + case RDIV_EXPR: + jopcode = OPCODE_idiv + adjust_typed_op (type); + goto binop; + binop: + generate_bytecode_insns (method, TREE_OPERAND (exp, 0), target); + generate_bytecode_insns (method, TREE_OPERAND (exp, 1), target); + if (target == STACK_TARGET) + { + RESERVE(1); + OP1 (jopcode); + } + break; + case CALL_EXPR: + { + tree t; + for (t = TREE_OPERAND (exp, 1); t != NULL_TREE; t = TREE_CHAIN (t)) + { + generate_bytecode_insns (method, TREE_VALUE (t), STACK_TARGET); + } + t = TREE_OPERAND (exp, 0); + if (TREE_CODE (t) == FUNCTION_DECL) + { + int index = find_methodref_index (code_cpool, t); + RESERVE (3); + if (DECL_CONSTRUCTOR_P (t)) + OP1 (OPCODE_invokespecial); + else if (METHOD_STATIC (t)) + OP1 (OPCODE_invokestatic); + else + OP1 (OPCODE_invokevirtual); + OP2 (index); + break; + } + } + /* fall through */ + default: + error("internal error - tree code not implemented: ", TREE_CODE (exp)); + } +} + +/* Generate and return a list of chunks containing the class CLAS + in the .class file representation. The list can be written to a + .class file using write_chunks. Allocate chunks from obstack WORK. */ + +/* Currently does not write any attributes i.e. no code. */ + +struct chunk * +generate_classfile (clas, work) + tree clas; + struct obstack *work; +{ + CPool cpool; + struct chunk head; + struct chunk *chunk; + struct chunk *cpool_chunk; + char *ptr; + int i; + char *fields_count_ptr; + int fields_count = 0; + char *methods_count_ptr; + int methods_count = 0; + tree part; + int total_supers + = clas == object_type_node ? 0 + : TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (clas)); + + chunk = alloc_chunk (&head, NULL, 8, work); + ptr = chunk->data; + PUT4 (0xCafeBabe); /* Magic number */ + PUT2 (3); /* Minor version */ + PUT2 (45); /* Major version */ + + CPOOL_INIT(&cpool); + cpool_chunk = chunk = alloc_chunk (chunk, NULL, 0, work); + + /* Next allocate the chunk containing acces_flags through fields_counr. */ + if (clas == object_type_node) + i = 10; + else + i = 8 + 2 * total_supers; + chunk = alloc_chunk (chunk, NULL, i, work); + ptr = chunk->data; + i = get_access_flags (TYPE_NAME (clas)); PUT2 (i); /* acces_flags */ + i = find_class_constant (&cpool, clas); PUT2 (i); /* this_class */ + if (clas == object_type_node) + { + PUT2(0); /* super_class */ + PUT2(0); /* interfaces_count */ + } + else + { + tree basetypes = TYPE_BINFO_BASETYPES (clas); + tree base = BINFO_TYPE (TREE_VEC_ELT (basetypes, 0)); + int j = find_class_constant (&cpool, base); PUT2 (j); /* super_class */ + PUT2 (total_supers - 1); /* interfaces_count */ + for (i = 1; i < total_supers; i++) + { + base = BINFO_TYPE (TREE_VEC_ELT (basetypes, i)); + j = find_class_constant (&cpool, base); + PUT2 (j); + } + } + fields_count_ptr = ptr; + + for (part = TYPE_FIELDS (clas); part; part = TREE_CHAIN (part)) + { + if (DECL_NAME (part) == NULL_TREE) + continue; + chunk = alloc_chunk (chunk, NULL, 8, work); + ptr = chunk->data; + i = get_access_flags (part); PUT2 (i); + i = find_utf8_constant (&cpool, DECL_NAME (part)); PUT2 (i); + i = find_utf8_constant (&cpool, build_java_signature (TREE_TYPE (part))); + PUT2(i); + PUT2 (0); /* attributes_count */ + /* FIXME - emit ConstantValue attribute when appropriate */ + fields_count++; + } + ptr = fields_count_ptr; PUT2 (fields_count); + + chunk = alloc_chunk (chunk, NULL, 2, work); + ptr = methods_count_ptr = chunk->data; + PUT2 (0); + + for (part = TYPE_METHODS (clas); part; part = TREE_CHAIN (part)) + { + tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (part)); + int linenumber_size; /* 4 * number of line number entries */ + chunk = alloc_chunk (chunk, NULL, 8, work); + ptr = chunk->data; + i = get_access_flags (part); PUT2 (i); + i = find_utf8_constant (&cpool, DECL_NAME (part)); PUT2 (i); + i = find_utf8_constant (&cpool, build_java_signature (TREE_TYPE (part))); + PUT2 (i); + PUT2 (body != NULL_TREE ? 1 : 0); /* attributes_count */ + if (body != NULL_TREE) + { + int code_attributes_count = 0; + int linenumber_size; /* 4 * number of line number entries */ + int localvartable_size; /* 10 * number of local variable entries */ + static tree Code_node = NULL_TREE; + tree t; + char *attr_len_ptr; + int code_length; + if (Code_node == NULL_TREE) + Code_node = get_identifier ("Code"); + chunk = alloc_chunk (chunk, NULL, 14, work); + ptr = chunk->data; + i = find_utf8_constant (&cpool, Code_node); PUT2 (i); + attr_len_ptr = ptr; + BUFFER_RESET (&bytecode); + BUFFER_RESET (&localvartable); + BUFFER_RESET (&linenumbers); + BUFFER_RESET (&localvars); + code_SP = 0; + code_SP_max = 0; + code_cpool = &cpool; + for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t)) + localvar_alloc (t, 0); + generate_bytecode_insns (part, body, IGNORE_TARGET); + code_length = PC; + for (t = DECL_ARGUMENTS (part); t != NULL_TREE; t = TREE_CHAIN (t)) + localvar_free (t, code_length); + linenumber_size = BUFFER_LENGTH (&linenumbers); + localvartable_size = BUFFER_LENGTH (&localvartable); + chunk = alloc_chunk (chunk, NULL, code_length, work); + bcopy (bytecode.data, chunk->data, code_length); + ptr = attr_len_ptr; + i = 8 + code_length + 4; + if (linenumber_size > 0) + { + code_attributes_count++; + i += 8 + linenumber_size; + } + if (localvartable_size > 0) + { + code_attributes_count++; + i += 8 + localvartable_size; + } + PUT4 (i); /* attribute_length */ + PUT2 (code_SP_max); /* max_stack */ + PUT2 (localvar_max); /* max_locals */ + PUT4 (code_length); + chunk = alloc_chunk (chunk, NULL, 4, work); + ptr = chunk->data; + PUT2 (0); /* exception_table_length */ + PUT2 (code_attributes_count); + + /* Write the LineNumberTable attribute. */ + if (linenumber_size > 0) + { + static tree LineNumberTable_node = NULL_TREE; + chunk = alloc_chunk (chunk, NULL, 8 + linenumber_size, work); + ptr = chunk->data; + if (LineNumberTable_node == NULL_TREE) + LineNumberTable_node = get_identifier ("LineNumberTable"); + i = find_utf8_constant (&cpool, LineNumberTable_node); + PUT2 (i); /* attribute_name_index */ + i = 2 + linenumber_size; PUT4 (i); /* attribute_length */ + i = linenumber_size >> 2; PUT2 (i); + PUTN (linenumbers.data, linenumber_size); + } + + /* Write the LocalVariableTable attribute. */ + if (localvartable_size > 0) + { + static tree LocalVariableTable_node = NULL_TREE; + chunk = alloc_chunk (chunk, NULL, 8 + localvartable_size, work); + ptr = chunk->data; + if (LocalVariableTable_node == NULL_TREE) + LocalVariableTable_node = get_identifier("LocalVariableTable"); + i = find_utf8_constant (&cpool, LocalVariableTable_node); + PUT2 (i); /* attribute_name_index */ + i = 2 + localvartable_size; PUT4 (i); /* attribute_length */ + i = localvartable_size / 10; PUT2 (i); + PUTN (localvartable.data, localvartable_size); + } + } + methods_count++; + } + ptr = methods_count_ptr; PUT2 (methods_count); + + chunk = alloc_chunk (chunk, NULL, 2, work); + ptr = chunk->data; + PUT2 (0); /* attributes_count */ + + /* New finally generate the contents of the constant pool chunk. */ + i = count_constant_pool_bytes (&cpool); + ptr = obstack_alloc (work, i); + cpool_chunk->data = ptr; + cpool_chunk->size = i; + write_constant_pool (&cpool, ptr, i); + CPOOL_FINISH (&cpool); + return head.next; +} + +char* +make_class_file_name (clas) + tree clas; +{ + /* Should prepend an output directly, but need an option to specify it. */ + return IDENTIFIER_POINTER (identifier_subst (DECL_NAME (TYPE_NAME (clas)), + "", '.', '/', ".class")); +} + +/* Write out the contens of a class (RECORD_TYPE) CLAS, as a .class file. + The output .class file name is make_class_file_name(CLAS). */ + +void +write_classfile (clas) + tree clas; +{ + struct obstack *work = &temporary_obstack; + char *class_file_name = make_class_file_name (clas); + struct chunk *chunks; + FILE* stream = fopen (class_file_name, "wb"); + if (stream == NULL) + fatal ("failed to open `%s' for writing", class_file_name); + chunks = generate_classfile (clas, work); + write_chunks (stream, chunks); + if (fclose (stream)) + fatal ("failed to close after writing `%s'", class_file_name); + obstack_free (work, chunks); +} diff --git a/gcc/java/jcf.h b/gcc/java/jcf.h new file mode 100644 index 00000000000..5e82387ca15 --- /dev/null +++ b/gcc/java/jcf.h @@ -0,0 +1,260 @@ +/* Utility macros to read Java(TM) .class files and byte codes. + + Copyright (C) 1996 Free Software Foundation, Inc. + +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, 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 GNU CC; 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. */ + +/* Written by Per Bothner , February 1996. */ + +#ifndef JCF_H +#define JCF_H +#include "javaop.h" +#ifndef DEFUN +#if defined (__STDC__) +#define AND , +#define PTR void * +#define DEFUN(name, arglist, args) name(args) +#else +#define PTR char * +#define AND ; +#define DEFUN(name, arglist, args) name arglist args; +#define inline static +#endif +#endif /* !DEFUN */ + +#ifndef PROTO +#if defined (__STDC__) +#define PROTO(paramlist) paramlist +#else +#define PROTO(paramlist) () +#endif +#endif + +#ifndef JCF_u4 +#define JCF_u4 unsigned long +#endif +#ifndef JCF_u2 +#define JCF_u2 unsigned short +#endif + +#define ALLOC (void*)malloc +#define REALLOC (void*)realloc +#ifndef FREE +#define FREE(PTR) free(PTR) +#endif + +#ifdef JCF_word +#define JCF_word JCF_u4 +#endif + +#define JCF_ZIP 1 +#define JCF_CLASS 2 +#define JCF_SOURCE 3 + +struct JCF; +typedef int (*jcf_filbuf_t) PROTO ((struct JCF*, int needed)); + +typedef struct CPool { + /* Available number of elements in the constants array, before it + must be re-allocated. */ + int capacity; + + /* The constant_pool_count. */ + int count; + + uint8* tags; + + jword* data; +} CPool; + +/* JCF encapsulates the state of reading a Java Class File. */ + +typedef struct JCF { + unsigned char *buffer; + unsigned char *buffer_end; + unsigned char *read_ptr; + unsigned char *read_end; + int seen_in_zip; + int java_source; + int outofsynch; /* Found a class file out of synch + with the matching source file. */ + long zip_offset; + jcf_filbuf_t filbuf; + void *read_state; + char *filename; + char *classname; + void *zipd; /* Directory entry where it was found */ + JCF_u2 access_flags, this_class, super_class; + CPool cpool; +} JCF; +/*typedef JCF* JCF_FILE;*/ + +/* The CPOOL macros take a (pointer to a) CPool. + The JPOOL macros take a (pointer to a) JCF. + Some of the latter should perhaps be deprecated or removed. */ + +#define CPOOL_COUNT(CPOOL) ((CPOOL)->count) +#define JPOOL_SIZE(JCF) CPOOL_COUNT(&(JCF)->cpool) +#define JPOOL_TAG(JCF, INDEX) ((JCF)->cpool.tags[INDEX]) +/* The INDEX'th constant pool entry as a JCF_u4. */ +#define CPOOL_UINT(CPOOL, INDEX) ((CPOOL)->data[INDEX]) +#define JPOOL_UINT(JCF, INDEX) CPOOL_UINT(&(JCF)->cpool, INDEX) /*deprecated*/ +/* The first uint16 of the INDEX'th constant pool entry. */ +#define CPOOL_USHORT1(CPOOL, INDEX) ((CPOOL)->data[INDEX] & 0xFFFF) +#define JPOOL_USHORT1(JCF, INDEX) CPOOL_USHORT1(&(JCF)->cpool, INDEX) +/* The second uint16 of the INDEX'th constant pool entry. */ +#define CPOOL_USHORT2(CPOOL, INDEX) ((CPOOL)->data[INDEX] >> 16) +#define JPOOL_USHORT2(JCF, INDEX) CPOOL_USHORT2(&(JCF)->cpool, INDEX) +#define JPOOL_LONG(JCF, INDEX) \ + WORDS_TO_LONG (JPOOL_UINT(JCF, INDEX), JPOOL_UINT(JCF, (INDEX)+1)) +#define JPOOL_DOUBLE(JCF, INDEX) \ + WORDS_TO_DOUBLE (JPOOL_UINT(JCF, INDEX), JPOOL_UINT(JCF, (INDEX)+1)) +#ifndef JPOOL_UTF_LENGTH +#define JPOOL_UTF_LENGTH(JCF, INDEX) \ + GET_u2 ((JCF)->buffer+JPOOL_UINT(JCF, INDEX)) +#endif +#ifndef JPOOL_UTF_DATA +#define JPOOL_UTF_DATA(JCF, INDEX) \ + ((JCF)->buffer+JPOOL_UINT(JCF, INDEX)+2) +#endif +#define JPOOL_INT(JCF, INDEX) ((jint) JPOOL_UINT (JCF, INDEX)) +#define JPOOL_FLOAT(JCF, INDEX) WORD_TO_FLOAT (JPOOL_UINT (JCF, INDEX)) + +#define CPOOL_INDEX_IN_RANGE(CPOOL, INDEX) \ + ((INDEX) > 0 && (INDEX) < CPOOL_COUNT(CPOOL)) + +#define CPOOL_FINISH(CPOOL) { \ + if ((CPOOL)->tags) FREE ((CPOOL)->tags); \ + if ((CPOOL)->data) FREE ((CPOOL)->data); } + +#define JCF_FINISH(JCF) { \ + CPOOL_FINISH(&(JCF)->cpool); \ + if ((JCF)->buffer) FREE ((JCF)->buffer); \ + if ((JCF)->filename) FREE ((JCF)->filename); \ + if ((JCF)->classname) FREE ((JCF)->classname); } + +#define CPOOL_INIT(CPOOL) \ + ((CPOOL)->capacity = 0, (CPOOL)->count = 0, (CPOOL)->tags = 0, (CPOOL)->data = 0) + +#define CPOOL_REINIT(CPOOL) ((CPOOL)->count = 0) + +#define JCF_ZERO(JCF) \ + ((JCF)->buffer = (JCF)->buffer_end = (JCF)->read_ptr = (JCF)->read_end = 0,\ + (JCF)->read_state = 0, (JCF)->filename = (JCF)->classname = 0, \ + CPOOL_INIT(&(JCF)->cpool), (JCF)->java_source = 0) + +/* Given that PTR points to a 2-byte unsigned integer in network + (big-endian) byte-order, return that integer. */ +#define GET_u2(PTR) (((PTR)[0] << 8) | ((PTR)[1])) +/* Like GET_u2, but for little-endian format. */ +#define GET_u2_le(PTR) (((PTR)[1] << 8) | ((PTR)[0])) + +/* Given that PTR points to a 4-byte unsigned integer in network + (big-endian) byte-order, return that integer. */ +#define GET_u4(PTR) (((JCF_u4)(PTR)[0] << 24) | ((JCF_u4)(PTR)[1] << 16) \ + | ((JCF_u4)(PTR)[2] << 8) | ((JCF_u4)(PTR)[3])) +/* Like GET_u4, but for little-endian order. */ +#define GET_u4_le(PTR) (((JCF_u4)(PTR)[3] << 24) | ((JCF_u4)(PTR)[2] << 16) \ + | ((JCF_u4)(PTR)[1] << 8) | ((JCF_u4)(PTR)[0])) + +/* Make sure there are COUNT bytes readable. */ +#define JCF_FILL(JCF, COUNT) \ + ((JCF)->read_end-(JCF)->read_ptr >= (COUNT) ? 0 : (*(JCF)->filbuf)(JCF, COUNT)) +#define JCF_GETC(JCF) (JCF_FILL(JCF, 1) ? -1 : *(JCF)->read_ptr++) +#define JCF_READ(JCF, BUFFER, N) \ + (memcpy (BUFFER, (JCF)->read_ptr, N), (JCF)->read_ptr += (N)) +#define JCF_SKIP(JCF,N) ((JCF)->read_ptr += (N)) +#define JCF_readu(JCF) (*(JCF)->read_ptr++) + +/* Reads an unsigned 2-byte integer in network (big-endian) byte-order + from JCF. Returns that integer. + Does not check for EOF (make sure to call JCF_FILL before-hand). */ +#define JCF_readu2(JCF) ((JCF)->read_ptr += 2, GET_u2 ((JCF)->read_ptr-2)) +#define JCF_readu2_le(JCF) ((JCF)->read_ptr += 2, GET_u2_le((JCF)->read_ptr-2)) + +/* Like JCF_readu2, but read a 4-byte unsigned integer. */ +#define JCF_readu4(JCF) ((JCF)->read_ptr += 4, GET_u4 ((JCF)->read_ptr-4)) +#define JCF_readu4_le(JCF) ((JCF)->read_ptr += 4, GET_u4_le((JCF)->read_ptr-4)) + +#define JCF_TELL(JCF) ((JCF)->read_ptr - (JCF)->buffer) +#define JCF_SEEK(JCF, POS) ((JCF)->read_ptr = (JCF)->buffer + (POS)) + +#define ACC_PUBLIC 0x0001 +#define ACC_PRIVATE 0x0002 +#define ACC_PROTECTED 0x0004 +#define ACC_STATIC 0x0008 +#define ACC_FINAL 0x0010 +#define ACC_SYNCHRONIZED 0x0020 +#define ACC_SUPER 0x0020 +#define ACC_VOLATILE 0x0040 +#define ACC_TRANSIENT 0x0080 +#define ACC_NATIVE 0x0100 +#define ACC_INTERFACE 0x0200 +#define ACC_ABSTRACT 0x0400 + +#define CONSTANT_Class 7 +#define CONSTANT_Fieldref 9 +#define CONSTANT_Methodref 10 +#define CONSTANT_InterfaceMethodref 11 +#define CONSTANT_String 8 +#define CONSTANT_Integer 3 +#define CONSTANT_Float 4 +#define CONSTANT_Long 5 +#define CONSTANT_Double 6 +#define CONSTANT_NameAndType 12 +#define CONSTANT_Utf8 1 +#define CONSTANT_Unicode 2 + +extern char *classpath; +#define DEFAULT_CLASS_PATH "." + +extern char *find_class PROTO ((const char *, int, JCF*, int)); +extern char *find_classfile PROTO ((char *, JCF*)); +extern int jcf_filbuf_from_stdio PROTO ((JCF *jcf, int count)); +extern void jcf_out_of_synch PROTO((JCF *)); +extern int jcf_unexpected_eof PROTO ((JCF*, int)); + +/* Extract a character from a Java-style Utf8 string. + * PTR points to the current character. + * LIMIT points to the end of the Utf8 string. + * PTR is incremented to point after the character thta gets returns. + * On an error, -1 is returned. */ +#define UTF8_GET(PTR, LIMIT) \ + ((PTR) >= (LIMIT) ? -1 \ + : *(PTR) < 128 ? *(PTR)++ \ + : (*(PTR)&0xE0) == 0xC0 && ((PTR)+=2)<=(LIMIT) && ((PTR)[-1]&0xC0) == 0x80 \ + ? (((PTR)[-2] & 0x1F) << 6) + ((PTR)[-1] & 0x3F) \ + : (*(PTR) & 0xF0) == 0xE0 && ((PTR) += 3) <= (LIMIT) \ + && ((PTR)[-2] & 0xC0) == 0x80 && ((PTR)[-1] & 0xC0) == 0x80 \ + ? (((PTR)[-3]&0x1F) << 12) + (((PTR)[-2]&0x3F) << 6) + ((PTR)[-1]&0x3F) \ + : ((PTR)++, -1)) + +/* Debug macros, for the front end */ + +extern int quiet_flag; +#ifdef SOURCE_FRONTEND_DEBUG +#undef SOURCE_FRONTEND_DEBUG +#define SOURCE_FRONTEND_DEBUG(X) \ + {if (!quiet_flag) {printf ("* "); printf X; putchar ('\n');} } +#else +#define SOURCE_FRONTEND_DEBUG(X) +#endif + +#endif diff --git a/gcc/java/jv-scan.c b/gcc/java/jv-scan.c new file mode 100644 index 00000000000..99065927756 --- /dev/null +++ b/gcc/java/jv-scan.c @@ -0,0 +1,235 @@ +/* Main for jv-scan + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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, +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 +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif + +#include "gansidecl.h" /* Definitions of PROTO and VPROTO */ +#include "obstack.h" /* We use obstacks in lex.c */ + +void fatal VPROTO((char *s, ...)); +void warning VPROTO((char *s, ...)); +void gcc_obstack_init PROTO ((struct obstack *obstack)); +extern void reset_report PROTO ((void)); + +#define JC1_LITE +#include "parse.h" + +/* Current input file and output file IO streams. */ +FILE *finput, *out; + +/* Current input filename. */ +char *input_filename; + +/* Executable name. */ +char *exec_name; + +/* Flags matching command line options. */ +int flag_find_main = 0; +int flag_dump_class = 0; +int flag_list_filename = 0; + +/* jc1-lite main entry point */ +int +main (argc, argv, envp) + int argc; + char **argv; + char **envp; +{ + int i = 1; + char *output_file = NULL; + long ft; + + exec_name = argv[0]; + + /* Default for output */ + out = stdout; + + /* Process options first */ + while (argv [i]) + { + if (argv [i][0] == '-') + { + /* Dump result into a file */ + if (!strcmp (argv [i], "-o") && i+1 < argc) + { + argv [i] = NULL; + output_file = argv [++i]; + argv [i] = NULL; + } + + /* Print the name of the class that contains main */ + else if (!strcmp (argv [i], "--print-main")) + flag_find_main = 1; + + else if (!strcmp (argv [i], "--list-filename")) + flag_list_filename = 1; + + /* List all the classes found in a source file */ + else if (!strcmp (argv [i], "--list-class")) + flag_dump_class = 1; + + else + warning ("Unrecognized argument `%s'", argv[i]); + + /* non recognized argument ignored silently */ + argv [i] = NULL; /* Nullify so it's not considered a file */ + } + i++; + } + + /* No flags? Do nothing */ + if (!flag_find_main && !flag_dump_class) + exit (0); + + /* Check on bad usage */ + if (flag_find_main && flag_dump_class) + fatal ("Options `--print-main' and `--list-class' can't be turned on " + "at the same time", argv [0]); + + if (output_file && !(out = fopen (output_file, "w"))) + fatal ("Can't open output file `%s'", argv [0], output_file); + + ft = ftell (out); + + gcc_obstack_init (&temporary_obstack); + java_push_parser_context (); + + for ( i = 1; i < argc; i++ ) + if (argv [i]) + { + input_filename = argv [i]; + if ( (finput = fopen (argv [i], "r")) ) + { + java_init_lex (); + yyparse (); + if (ftell (out) != ft) + fputc ('\n', out); + ft = ftell (out); + fclose (finput); + reset_report (); + } + else + fatal ("File not found `%s'", argv [0], argv [i]); + } + + /* Flush and close */ + if (ftell (out) != ft) + fputc ('\n', out); + if (!output_file) + fclose (out); + + exit (0); +} + +/* Error report, memory, obstack initialization and other utility + functions */ + +void +fatal VPROTO((char *s, ...)) +{ +#ifndef __STDC__ + char *s; +#endif + va_list ap; + + VA_START (ap, s); + +#ifndef __STDC__ + s = va_arg (ap, char *); +#endif + + fprintf (stderr, "%s: error: ", exec_name); + vfprintf (stderr, s, ap); + fputc ('\n', stderr); + va_end (ap); + exit (1); +} + +char * +xmalloc (size) + unsigned size; +{ + register char *value; + + if (size == 0) + size = 1; + + value = (char *) malloc (size); + if (value == 0) + fatal ("virtual memory exhausted"); + return value; +} + +char * +xstrdup (string) + char *string; +{ + int length = strlen (string)+1; + char *to_return = xmalloc (length); + strcpy (to_return, string); + return to_return; +} + +void +warning VPROTO((char *s, ...)) +{ +#ifndef __STDC__ + char *s; +#endif + va_list ap; + + VA_START (ap, s); + +#ifndef __STDC__ + s = va_arg (ap, char *); +#endif + + fprintf (stderr, "%s: warning: ", exec_name); + vfprintf (stderr, s, ap); + fputc ('\n', stderr); + va_end (ap); +} + +void +gcc_obstack_init (obstack) + struct obstack *obstack; +{ + /* Let particular systems override the size of a chunk. */ +#ifndef OBSTACK_CHUNK_SIZE +#define OBSTACK_CHUNK_SIZE 0 +#endif + /* Let them override the alloc and free routines too. */ +#ifndef OBSTACK_CHUNK_ALLOC +#define OBSTACK_CHUNK_ALLOC xmalloc +#endif +#ifndef OBSTACK_CHUNK_FREE +#define OBSTACK_CHUNK_FREE free +#endif + _obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0, + (void *(*) ()) OBSTACK_CHUNK_ALLOC, + (void (*) ()) OBSTACK_CHUNK_FREE); +} diff --git a/gcc/java/jvgenmain.c b/gcc/java/jvgenmain.c new file mode 100644 index 00000000000..ce7c60a315e --- /dev/null +++ b/gcc/java/jvgenmain.c @@ -0,0 +1,124 @@ +/* Program to generate "main" a Java(TM) class containing a main method. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Written by Per Bothner */ + +#include +#include +#include "config.h" +#include "obstack.h" + +const char main_method_prefix[] = "main__"; +const char main_method_suffix[] = "Pt6JArray1ZPQ34java4lang6String"; +const char class_mangling_prefix[] = "_CL_"; + +struct obstack name_obstack; + +void +error (const char *str) +{ + fprintf (stderr, "%s\n", str); + exit (-1); +} + +void * +xmalloc (size) + size_t size; +{ + void *ptr = malloc (size); + if (ptr == NULL) + { + fprintf (stderr, "Not enough memory!\n"); + exit (-1); + } + return ptr; +} + +void +gcc_obstack_init (obstack) + struct obstack *obstack; +{ + /* Let particular systems override the size of a chunk. */ +#ifndef OBSTACK_CHUNK_SIZE +#define OBSTACK_CHUNK_SIZE 0 +#endif + /* Let them override the alloc and free routines too. */ +#ifndef OBSTACK_CHUNK_ALLOC +#define OBSTACK_CHUNK_ALLOC xmalloc +#endif +#ifndef OBSTACK_CHUNK_FREE +#define OBSTACK_CHUNK_FREE free +#endif + _obstack_begin (obstack, OBSTACK_CHUNK_SIZE, 0, + (void *(*) ()) OBSTACK_CHUNK_ALLOC, + (void (*) ()) OBSTACK_CHUNK_FREE); +} + +int +main (int argc, const char **argv) +{ + const char *classname; + FILE *stream; + char *mangled_classname; + + if (argc < 2 || argc > 3) + { + fprintf (stderr, "Usage: %s CLASSNAME [OUTFILE]\n", argv[0]); + exit(-1); + } + + classname = argv[1]; + + gcc_obstack_init (&name_obstack); + append_gpp_mangled_classtype (&name_obstack, classname); + mangled_classname = obstack_finish (&name_obstack); + + if (argc > 2 && strcmp (argv[2], "-") != 0) + { + const char *outfile = argv[2]; + stream = fopen (outfile, "w"); + if (stream == NULL) + { + fprintf (stderr, "%s: Cannot open output file: %s\n", + argv[0], outfile); + exit (-1); + } + } + else + stream = stdout; + fprintf (stream, "extern struct Class %s%s;\n", + class_mangling_prefix, mangled_classname); + fprintf (stream, "int main (int argc, const char **argv)\n"); + fprintf (stream, "{\n"); + fprintf (stream, " JvRunMain (&%s%s, argc, argv);\n", + class_mangling_prefix, mangled_classname); + fprintf (stream, "}\n"); + if (stream != stdout && fclose (stream) != 0) + { + fprintf (stderr, "%s: Failed to close output file %s\n", + argv[0], argv[2]); + exit (-1); + } + return 0; +} diff --git a/gcc/java/jvspec.c b/gcc/java/jvspec.c new file mode 100644 index 00000000000..5f9381167d8 --- /dev/null +++ b/gcc/java/jvspec.c @@ -0,0 +1,357 @@ +/* Specific flags and argument handling of the front-end of the + GNU compiler for the Java(TM) language. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +#include "config.h" + +#include "system.h" + +#include "gansidecl.h" + +#if defined (WITH_THREAD_posix) || defined (WITH_THREAD_pthreads) +#define THREAD_NAME "-lpthread" +#elif defined (WITH_THREAD_qt) +#define THREAD_NAME "-lqthreads" +#endif + +/* This bit is set if we saw a `-xfoo' language specification. */ +#define LANGSPEC (1<<1) +/* This bit is set if they did `-lm' or `-lmath'. */ +#define MATHLIB (1<<2) +/* This bit is set if they did `-lc'. */ +#define WITHLIBC (1<<3) +/* This bit is set if they did `-lgc'. */ +#define GCLIB (1<<4) +/* This bit is set if they did `-lpthread' (or added some other thread + library). */ +#define THREADLIB (1<<5) + +#ifndef MATH_LIBRARY +#define MATH_LIBRARY "-lm" +#endif + +extern char *xmalloc PROTO((size_t)); +extern int do_spec PROTO((char *)); +extern char *input_filename; +extern size_t input_filename_length; + +char *main_class_name = NULL; +int lang_specific_extra_outfiles = 0; + +char jvgenmain_spec[] = + "jvgenmain %i %{!pipe:%g.i} |\n\ + cc1 %{!pipe:%g.i} %1 \ + %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a*}\ + %{g*} %{O*} \ + %{v:-version} %{pg:-p} %{p} %{f*}\ + %{aux-info*}\ + %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ + %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ + %{!S:as %a %Y -o %w%b%O %{!pipe:%g.s} %A\n }"; + +void +lang_specific_driver (fn, in_argc, in_argv, in_added_libraries) + void (*fn)(); + int *in_argc; + char ***in_argv; + int *in_added_libraries; +{ + int i, j; + + /* If non-zero, the user gave us the `-v' flag. */ + int saw_verbose_flag = 0; + + /* This will be 0 if we encounter a situation where we should not + link in libjava. */ + int library = 1; + + /* The number of arguments being added to what's in argv, other than + libraries. We use this to track the number of times we've inserted + -xc++/-xnone. */ + int added = 2; + + /* Used to track options that take arguments, so we don't go wrapping + those with -xc++/-xnone. */ + char *quote = NULL; + + /* The new argument list will be contained in this. */ + char **arglist; + + /* Non-zero if we saw a `-xfoo' language specification on the + command line. Used to avoid adding our own -xc++ if the user + already gave a language for the file. */ + int saw_speclang = 0; + + /* "-lm" or "-lmath" if it appears on the command line. */ + char *saw_math = 0; + + /* "-lc" if it appears on the command line. */ + char *saw_libc = 0; + + /* "-lgc" if it appears on the command line. */ + char *saw_gc = 0; + + /* Saw `-l' option for the thread library. */ + char *saw_threadlib = 0; + + /* Saw `-ljava' on command line. */ + int saw_libjava = 0; + + /* An array used to flag each argument that needs a bit set for + LANGSPEC, MATHLIB, WITHLIBC, or GCLIB. */ + int *args; + + /* By default, we throw on the math library. */ + int need_math = 1; + + /* By default, we throw in the thread library (if one is required). + */ + int need_thread = 1; + + /* The total number of arguments with the new stuff. */ + int argc; + + /* The argument list. */ + char **argv; + + /* The number of libraries added in. */ + int added_libraries; + + /* The total number of arguments with the new stuff. */ + int num_args = 1; + + argc = *in_argc; + argv = *in_argv; + added_libraries = *in_added_libraries; + + args = (int *) xmalloc (argc * sizeof (int)); + bzero ((char *) args, argc * sizeof (int)); + + for (i = 1; i < argc; i++) + { + /* If the previous option took an argument, we swallow it here. */ + if (quote) + { + quote = NULL; + continue; + } + + /* We don't do this anymore, since we don't get them with minus + signs on them. */ + if (argv[i][0] == '\0' || argv[i][1] == '\0') + continue; + + if (argv[i][0] == '-') + { + if (library != 0 && (strcmp (argv[i], "-nostdlib") == 0 + || strcmp (argv[i], "-nodefaultlibs") == 0)) + { + library = 0; + } + else if (strcmp (argv[i], "-lm") == 0 + || strcmp (argv[i], "-lmath") == 0 +#ifdef ALT_LIBM + || strcmp (argv[i], ALT_LIBM) == 0 +#endif + ) + { + args[i] |= MATHLIB; + need_math = 0; + } + else if (strncmp (argv[i], "-fmain=", 7) == 0) + main_class_name = argv[i] + 7; + else if (strcmp (argv[i], "-ljava") == 0) + saw_libjava = 1; + else if (strcmp (argv[i], "-lc") == 0) + args[i] |= WITHLIBC; + else if (strcmp (argv[i], "-lgc") == 0) + args[i] |= GCLIB; +#ifdef THREAD_NAME + else if (strcmp (argv[i], THREAD_NAME) == 0) + { + args[i] |= THREADLIB; + need_thread = 0; + } +#endif + else if (strcmp (argv[i], "-v") == 0) + { + saw_verbose_flag = 1; + if (argc == 2) + { + /* If they only gave us `-v', don't try to link + in libjava. */ + library = 0; + } + } + else if (strncmp (argv[i], "-x", 2) == 0) + saw_speclang = 1; + else if (((argv[i][2] == '\0' + && (char *)strchr ("bBVDUoeTuIYmLiA", argv[i][1]) != NULL) + || strcmp (argv[i], "-Tdata") == 0)) + quote = argv[i]; + else if (library != 0 && ((argv[i][2] == '\0' + && (char *) strchr ("cSEM", argv[i][1]) != NULL) + || strcmp (argv[i], "-MM") == 0)) + { + /* Don't specify libraries if we won't link, since that would + cause a warning. */ + library = 0; + added -= 2; + } + else + /* Pass other options through. */ + continue; + } + else + { + int len; + + if (saw_speclang) + { + saw_speclang = 0; + continue; + } + + /* If the filename ends in .c or .i, put options around it. + But not if a specified -x option is currently active. */ + len = strlen (argv[i]); + if (len > 2 + && (argv[i][len - 1] == 'c' || argv[i][len - 1] == 'i') + && argv[i][len - 2] == '.') + { + args[i] |= LANGSPEC; + added += 2; + } + } + } + + if (quote) + (*fn) ("argument to `%s' missing\n", quote); + + /* If we know we don't have to do anything, bail now. */ + if (! added && ! library && main_class_name == NULL) + { + free (args); + return; + } + + num_args = argc + added + need_math + need_thread; + if (main_class_name) + { + lang_specific_extra_outfiles++; + } + arglist = (char **) xmalloc (num_args * sizeof (char *)); + + /* NOTE: We start at 1 now, not 0. */ + for (i = 0, j = 0; i < argc; i++, j++) + { + arglist[j] = argv[i]; + + if (strncmp (argv[i], "-fmain=", 7) == 0) + { + --j; + continue; + } + + /* Make sure -ljava is before the math library, since libjava + itself uses those math routines. */ + if (!saw_math && (args[i] & MATHLIB) && library) + { + --j; + saw_math = argv[i]; + } + + /* Likewise -ljava must come before -lc. */ + if (!saw_libc && (args[i] & WITHLIBC) && library) + { + --j; + saw_libc = argv[i]; + } + + /* And -ljava must come before -lgc. */ + if (!saw_gc && (args[i] & GCLIB) && library) + { + --j; + saw_gc = argv[i]; + } + + /* And -ljava must come before thread library. */ + if (!saw_threadlib && (args[i] & THREADLIB) && library) + { + --j; + saw_threadlib = argv[i]; + } + } + + /* Add `-ljava' if we haven't already done so. */ + if (library && ! saw_libjava) + { + arglist[j++] = "-ljava"; + added_libraries++; + } + + if (saw_math) + arglist[j++] = saw_math; + else if (library) + { + arglist[j++] = MATH_LIBRARY; + added_libraries++; + } + + /* FIXME: we need a way to know when the GC library should be + added. Then we can add it if the user hasn't already. */ + if (saw_gc) + arglist[j++] = saw_gc; + + /* Thread library must come after GC library as well as after + -ljava. */ + if (saw_threadlib) + arglist[j++] = saw_threadlib; +#ifdef THREAD_NAME + else if (library) + { + arglist[j++] = THREAD_NAME; + added_libraries++; + } +#endif + + if (saw_libc) + arglist[j++] = saw_libc; + + arglist[j] = NULL; + + *in_argc = j; + *in_argv = arglist; + *in_added_libraries = added_libraries; +} + +int +lang_specific_pre_link () +{ + if (main_class_name == NULL) + return 0; + input_filename = main_class_name; + input_filename_length = strlen (main_class_name); + return do_spec (jvgenmain_spec); +} diff --git a/gcc/java/keyword.gperf b/gcc/java/keyword.gperf new file mode 100644 index 00000000000..38f02572809 --- /dev/null +++ b/gcc/java/keyword.gperf @@ -0,0 +1,80 @@ +%{ +/* Keyword definition for the GNU compiler for the Java(TM) language. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +%} +struct java_keyword { char *name; int token; }; +%% +abstract, ABSTRACT_TK +default, DEFAULT_TK +if, IF_TK +private, PRIVATE_TK +throw, THROW_TK +boolean, BOOLEAN_TK +do, DO_TK +implements, IMPLEMENTS_TK +protected, PROTECTED_TK +throws, THROWS_TK +break, BREAK_TK +double, DOUBLE_TK +import, IMPORT_TK +public, PUBLIC_TK +transient, TRANSIENT_TK +byte, BYTE_TK +else, ELSE_TK +instanceof, INSTANCEOF_TK +return, RETURN_TK +try, TRY_TK +case, CASE_TK +extends, EXTENDS_TK +int, INT_TK +short, SHORT_TK +void, VOID_TK +catch, CATCH_TK +final, FINAL_TK +interface, INTERFACE_TK +static, STATIC_TK +volatile, VOLATILE_TK +char, CHAR_TK +finally, FINALLY_TK +long, LONG_TK +super, SUPER_TK +while, WHILE_TK +class, CLASS_TK +float, FLOAT_TK +native, NATIVE_TK +switch, SWITCH_TK +const, CONST_TK +for, FOR_TK +new, NEW_TK +synchronized, SYNCHRONIZED_TK +continue, CONTINUE_TK +goto, GOTO_TK +package, PACKAGE_TK +this, THIS_TK +# true, false and null aren't keyword. But we match them easily this way +true, TRUE_TK +false, FALSE_TK +null, NULL_TK diff --git a/gcc/java/keyword.h b/gcc/java/keyword.h new file mode 100644 index 00000000000..c9bd1711c44 --- /dev/null +++ b/gcc/java/keyword.h @@ -0,0 +1,165 @@ +/* C code produced by gperf version 2.5 (GNU C++ version) */ +/* Command-line: gperf -p -t -j1 -i 1 -g -o -N java_keyword -k1,3,$ keyword.gperf */ +/* Keyword definitions for the GNU compiler for the Java(TM) language. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +struct java_keyword { char *name; int token; }; + +#define TOTAL_KEYWORDS 50 +#define MIN_WORD_LENGTH 2 +#define MAX_WORD_LENGTH 12 +#define MIN_HASH_VALUE 6 +#define MAX_HASH_VALUE 86 +/* maximum key range = 81, duplicates = 0 */ + +#ifdef __GNUC__ +inline +#endif +static unsigned int +hash (str, len) + register char *str; + register int unsigned len; +{ + static unsigned char asso_values[] = + { + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 87, 87, 87, + 87, 87, 87, 87, 87, 87, 87, 18, 37, 38, + 27, 1, 30, 3, 12, 8, 87, 2, 11, 87, + 8, 1, 5, 87, 24, 1, 1, 30, 2, 36, + 87, 1, 87, 87, 87, 87, 87, 87, + }; + register int hval = len; + + switch (hval) + { + default: + case 3: + hval += asso_values[str[2]]; + case 2: + case 1: + hval += asso_values[str[0]]; + break; + } + return hval + asso_values[str[len - 1]]; +} + +#ifdef __GNUC__ +inline +#endif +struct java_keyword * +java_keyword (str, len) + register char *str; + register unsigned int len; +{ + static struct java_keyword wordlist[] = + { + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"try", TRY_TK}, + {"else", ELSE_TK}, + {"short", SHORT_TK}, + {"goto", GOTO_TK}, + {"extends", EXTENDS_TK}, + {"",}, {"",}, + {"int", INT_TK}, + {"this", THIS_TK}, + {"",}, + {"native", NATIVE_TK}, + {"",}, {"",}, + {"interface", INTERFACE_TK}, + {"import", IMPORT_TK}, + {"private", PRIVATE_TK}, + {"volatile", VOLATILE_TK}, + {"",}, + {"implements", IMPLEMENTS_TK}, + {"",}, + {"long", LONG_TK}, + {"switch", SWITCH_TK}, + {"abstract", ABSTRACT_TK}, + {"transient", TRANSIENT_TK}, + {"do", DO_TK}, + {"",}, + {"throws", THROWS_TK}, + {"",}, + {"null", NULL_TK}, + {"super", SUPER_TK}, + {"true", TRUE_TK}, + {"float", FLOAT_TK}, + {"",}, + {"return", RETURN_TK}, + {"if", IF_TK}, + {"void", VOID_TK}, + {"protected", PROTECTED_TK}, + {"byte", BYTE_TK}, + {"case", CASE_TK}, + {"break", BREAK_TK}, + {"finally", FINALLY_TK}, + {"false", FALSE_TK}, + {"synchronized", SYNCHRONIZED_TK}, + {"instanceof", INSTANCEOF_TK}, + {"while", WHILE_TK}, + {"package", PACKAGE_TK}, + {"const", CONST_TK}, + {"boolean", BOOLEAN_TK}, + {"final", FINAL_TK}, + {"continue", CONTINUE_TK}, + {"catch", CATCH_TK}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"class", CLASS_TK}, + {"static", STATIC_TK}, + {"double", DOUBLE_TK}, + {"default", DEFAULT_TK}, + {"throw", THROW_TK}, + {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, {"",}, + {"",}, {"",}, {"",}, {"",}, {"",}, + {"for", FOR_TK}, + {"",}, + {"new", NEW_TK}, + {"char", CHAR_TK}, + {"",}, + {"public", PUBLIC_TK}, + }; + + if (len <= MAX_WORD_LENGTH && len >= MIN_WORD_LENGTH) + { + register int key = hash (str, len); + + if (key <= MAX_HASH_VALUE && key >= 0) + { + register char *s = wordlist[key].name; + + if (*s == *str && !strcmp (str + 1, s + 1)) + return &wordlist[key]; + } + } + return 0; +} diff --git a/gcc/java/lang-options.h b/gcc/java/lang-options.h new file mode 100644 index 00000000000..f421e6a16c7 --- /dev/null +++ b/gcc/java/lang-options.h @@ -0,0 +1,35 @@ +/* Switch definitions for the GNU compiler for the Java(TM) language. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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 is the contribution to the `lang_options' array in gcc.c for + java. */ + +DEFINE_LANG_NAME ("Java") + + { "-fbounds-check", "" }, + { "-fno-bounds-check", "Disable automatic array bounds checking" }, + { "-fassume-compiled", "Make is_compiled_class return 1"}, + { "-fno-assume-compiled", "" }, + { "-femit-class-file", "" }, + { "-femit-class-files", "Dump class files to .class" }, diff --git a/gcc/java/lang-specs.h b/gcc/java/lang-specs.h new file mode 100644 index 00000000000..f86c327d0c0 --- /dev/null +++ b/gcc/java/lang-specs.h @@ -0,0 +1,38 @@ +/* Definitions for specs for the GNU compiler for the Java(TM) language. + Copyright (C) 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, 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 is the contribution to the `default_compilers' array in gcc.c for + Java. */ + + {".java", "@java" }, + {".class", "@java" }, + {"@java", + "%{!M:%{!MM:%{!E:jc1 %i %1 %2 %{!Q:-quiet} %{d*} %{m*} %{a}\ + %{g*} %{O*} %{W*} %{w} %{pedantic*} %{ansi}\ + %{traditional} %{v:-version} %{pg:-p} %{p}\ + %{f*} %{+e*} %{aux-info*}\ + %{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\ + %{S:%W{o*}%{!o*:-o %b.s}}%{!S:-o %{|!pipe:%g.s}} |\n\ + %{!S:as %a %Y\ + %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}\ + %{!pipe:%g.s} %A\n }}}}"}, diff --git a/gcc/java/lang.c b/gcc/java/lang.c new file mode 100644 index 00000000000..ddaff0cc6b5 --- /dev/null +++ b/gcc/java/lang.c @@ -0,0 +1,406 @@ +/* Java(TM) language-specific utility routines. + Copyright (C) 1996, 1997, 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Hacked by Per Bothner February 1996. */ + +#include +#include "config.h" +#include "tree.h" +#include "input.h" +#include "java-tree.h" +#include "jcf.h" + +int compiling_from_source; + +char *language_string = "GNU Java"; + +/* Nonzero if we want to automatically do array bounds checking; + on by default. Use -fno-bounds-check to disable. */ + +int flag_bounds_check = 1; + +/* Nonzero if we should make is_compiled_class always return 1 for + appropriate classes that we're referencing. */ + +int flag_assume_compiled = 1; + +int flag_emit_class_files = 0; + +/* From gcc/flags.h, and idicates if exceptions are turned on or not. */ + +extern int flag_new_exceptions; +extern int flag_exceptions; + +/* Table of language-dependent -f options. + STRING is the option name. VARIABLE is the address of the variable. + ON_VALUE is the value to store in VARIABLE + if `-fSTRING' is seen as an option. + (If `-fno-STRING' is seen as an option, the opposite value is stored.) */ + +static struct { char *string; int *variable; int on_value;} lang_f_options[] = +{ + {"bounds-check", &flag_bounds_check, 1}, + {"assume-compiled", &flag_assume_compiled, 1}, + {"emit-class-file", &flag_emit_class_files, 1}, + {"emit-class-files", &flag_emit_class_files, 1}, +}; + +JCF main_jcf[1]; +JCF *current_jcf; + +/* + * process java-specific compiler command-line options + */ +int +lang_decode_option (argc, argv) + int argc; + char **argv; +{ + char *p = argv[0]; + if (p[0] == '-' && p[1] == 'f') + { + /* Some kind of -f option. + P's value is the option sans `-f'. + Search for it in the table of options. */ + int found = 0, j; + + p += 2; + + for (j = 0; + !found && j < sizeof (lang_f_options) / sizeof (lang_f_options[0]); + j++) + { + if (!strcmp (p, lang_f_options[j].string)) + { + *lang_f_options[j].variable = lang_f_options[j].on_value; + /* A goto here would be cleaner, + but breaks the vax pcc. */ + found = 1; + } + if (p[0] == 'n' && p[1] == 'o' && p[2] == '-' + && ! strcmp (p+3, lang_f_options[j].string)) + { + *lang_f_options[j].variable = ! lang_f_options[j].on_value; + found = 1; + } + } + return found; + } + + return 0; +} + +FILE *finput; +char * +init_parse (filename) + char *filename; +{ + /* Open input file. */ + + if (filename == 0 || !strcmp (filename, "-")) + { + finput = stdin; + filename = "stdin"; + } + else + finput = fopen (filename, "r"); + if (finput == 0) + pfatal_with_name (filename); + +#ifdef IO_BUFFER_SIZE + setvbuf (finput, (char *) xmalloc (IO_BUFFER_SIZE), _IOFBF, IO_BUFFER_SIZE); +#endif + init_lex (); + + return filename; +} + +void +finish_parse () +{ + fclose (finput); +} + +/* Buffer used by lang_printable_name. */ +static char *decl_buf = NULL; + +/* Allocated size of decl_buf. */ +static int decl_buflen = 0; + +/* Length of used part of decl_buf; position for next character. */ +static int decl_bufpos = 0; + +/* Append the string STR to decl_buf. + It length is given by LEN; -1 means the string is nul-terminated. */ + +static void +put_decl_string (str, len) + char *str; + int len; +{ + if (len < 0) + len = strlen (str); + if (decl_bufpos + len >= decl_buflen) + { + if (decl_buf == NULL) + { + decl_buflen = len + 100; + decl_buf = (char *) xmalloc (decl_buflen); + } + else + { + decl_buflen *= 2; + decl_buf = (char *) xrealloc (decl_buf, decl_buflen); + } + } + strcpy (decl_buf + decl_bufpos, str); + decl_bufpos += len; +} + +/* Append to decl_buf a printable name for NODE. */ + +static void +put_decl_node (node) + tree node; +{ + int was_pointer = 0; + if (TREE_CODE (node) == POINTER_TYPE) + { + node = TREE_TYPE (node); + was_pointer = 1; + } + if (TREE_CODE_CLASS (TREE_CODE (node)) == 'd' + && DECL_NAME (node) != NULL_TREE) + { +#if 0 + if (DECL_CONTEXT (node) != NULL_TREE) + { + put_decl_node (DECL_CONTEXT (node)); + put_decl_string (".", 1); + } +#endif + put_decl_node (DECL_NAME (node)); + if (TREE_CODE (node) == FUNCTION_DECL && TREE_TYPE (node) != NULL_TREE) + { + int i = 0; + tree args = TYPE_ARG_TYPES (TREE_TYPE (node)); + if (TREE_CODE (TREE_TYPE (node)) == METHOD_TYPE) + args = TREE_CHAIN (args); + put_decl_string ("(", 1); + for ( ; args != NULL_TREE; args = TREE_CHAIN (args), i++) + { + if (i > 0) + put_decl_string (",", 1); + put_decl_node (TREE_VALUE (args)); + } + put_decl_string (")", 1); + } + } + else if (TREE_CODE_CLASS (TREE_CODE (node)) == 't' + && TYPE_NAME (node) != NULL_TREE) + { + if (TREE_CODE (node) == RECORD_TYPE && TYPE_ARRAY_P (node)) + { + put_decl_node (TYPE_ARRAY_ELEMENT (node)); + put_decl_string("[]", 2); + } + else if (node == promoted_byte_type_node) + put_decl_string ("byte", 4); + else if (node == promoted_short_type_node) + put_decl_string ("short", 5); + else if (node == promoted_char_type_node) + put_decl_string ("char", 4); + else if (node == promoted_boolean_type_node) + put_decl_string ("boolean", 7); + else if (node == void_type_node && was_pointer) + put_decl_string ("null", 4); + else + put_decl_node (TYPE_NAME (node)); + } + else if (TREE_CODE (node) == IDENTIFIER_NODE) + put_decl_string (IDENTIFIER_POINTER (node), IDENTIFIER_LENGTH (node)); + else + put_decl_string ("", -1); +} + +/* Return a user-friendly name for DECL. + The resulting string is only valid until the next call. + The value of the hook decl_printable_name is this function, + which is also called directly by lang_print_error. */ + +char * +lang_printable_name (decl, v) + tree decl; + int v; +{ + decl_bufpos = 0; + put_decl_node (decl); + put_decl_string ("", 1); + return decl_buf; +} + +/* Print on stderr the current class and method context. This function + is the value of the hook print_error_function, called from toplev.c. */ + +void +lang_print_error (file) + char *file; +{ + static tree last_error_function_context = NULL_TREE; + static tree last_error_function = NULL; + + if (current_function_decl != NULL + && DECL_CONTEXT (current_function_decl) != last_error_function_context) + { + if (file) + fprintf (stderr, "%s: ", file); + + last_error_function_context = DECL_CONTEXT (current_function_decl); + fprintf (stderr, "In class `%s':\n", + lang_printable_name (last_error_function_context)); + } + if (last_error_function != current_function_decl) + { + if (file) + fprintf (stderr, "%s: ", file); + + if (current_function_decl == NULL) + fprintf (stderr, "At top level:\n"); + else + { + char *name = lang_printable_name (current_function_decl, 2); + fprintf (stderr, "In method `%s':\n", name); + } + + last_error_function = current_function_decl; + } + +} + +void +lang_init () +{ + extern struct rtx_def * java_lang_expand_expr (); + extern struct rtx_def * (*lang_expand_expr) (); + extern void (*print_error_function) PROTO((char *)); +#if 0 + extern int flag_minimal_debug; + flag_minimal_debug = 0; +#endif + + decl_printable_name = lang_printable_name; + print_error_function = lang_print_error; + lang_expand_expr = java_lang_expand_expr; + + JCF_ZERO (main_jcf); + main_jcf->read_state = finput; + main_jcf->filbuf = jcf_filbuf_from_stdio; + current_jcf = main_jcf; + + flag_exceptions = 1; +} + +/* This doesn't do anything on purpose. It's used to satisfy the + print_error_function hook we don't print error messages with bogus + function prototypes. */ + +void java_dummy_print (s) + char *s; +{ +} + +/* Called to install the PRINT_ERROR_FUNCTION hook differently + according to LEVEL. LEVEL is 1 during early parsing, when function + prototypes aren't fully resolved. print_error_function is set so it + doesn't print incomplete function prototypes. When LEVEL is 2, + function prototypes are fully resolved and can be printed when + reporting errors. */ + +void lang_init_source (level) + int level; +{ + extern void (*print_error_function) PROTO((char *)); + if (level == 1) + print_error_function = java_dummy_print; + else + print_error_function = lang_print_error; +} + +void +lang_init_options () +{ + flag_new_exceptions = 1; +} + +void +lang_finish () +{ +} + +char* +lang_identify () +{ + return "Java"; +} + +/* Hooks for print_node. */ + +void +print_lang_decl (file, node, indent) + FILE *file; + tree node; + int indent; +{ +} + +void +print_lang_type (file, node, indent) + FILE *file; + tree node; + int indent; +{ +} + +void +print_lang_identifier (file, node, indent) + FILE *file; + tree node; + int indent; +{ +} + +void +print_lang_statistics () +{ +} + +/* used by print-tree.c */ + +void +lang_print_xnode (file, node, indent) + FILE *file; + tree node; + int indent; +{ +} diff --git a/gcc/java/lex.c b/gcc/java/lex.c new file mode 100644 index 00000000000..50999654766 --- /dev/null +++ b/gcc/java/lex.c @@ -0,0 +1,1355 @@ +/* Language lexer for the GNU compiler for the Java(TM) language. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* It defines java_lex (yylex) that reads a Java ASCII source file +possibly containing Unicode escape sequence or utf8 encoded characters +and returns a token for everything found but comments, white spaces +and line terminators. When necessary, it also fills the java_lval +(yylval) union. It's implemented to be called by a re-entrant parser +generated by Bison. + +The lexical analysis conforms to the Java grammar described in "The +Java(TM) Language Specification. J. Gosling, B. Joy, G. Steele. +Addison Wesley 1996" (http://java.sun.com/docs/books/jls/html/3.doc.html) */ + +#include +#include +#include + +#ifdef JAVA_LEX_DEBUG +#include +#endif + +#ifdef inline /* javaop.h redefines inline as static */ +#undef inline +#endif +#include "keyword.h" + +#ifndef SEEK_SET +#include +#endif + +void +java_init_lex () +{ + int java_lang_imported = 0; + +#ifndef JC1_LITE + if (!java_lang_imported) + { + tree node = build_tree_list + (build_expr_wfl (get_identifier ("java.lang"), NULL, 0, 0), NULL_TREE); + read_import_dir (TREE_PURPOSE (node)); + TREE_CHAIN (node) = ctxp->import_demand_list; + ctxp->import_demand_list = node; + java_lang_imported = 1; + } + + if (!wfl_operator) + wfl_operator = build_expr_wfl (NULL_TREE, ctxp->filename, 0, 0); + if (!label_id) + label_id = get_identifier ("$L"); + + ctxp->static_initialized = ctxp->non_static_initialized = + ctxp->incomplete_class = NULL_TREE; + + bzero (ctxp->modifier_ctx, 11*sizeof (ctxp->modifier_ctx[0])); + classpath = NULL; + bzero (current_jcf, sizeof (JCF)); + ctxp->current_parsed_class = NULL; + ctxp->package = NULL_TREE; +#endif + + ctxp->filename = input_filename; + ctxp->lineno = lineno = 0; + ctxp->p_line = NULL; + ctxp->c_line = NULL; + ctxp->unget_utf8_value = 0; + ctxp->minus_seen = 0; + ctxp->java_error_flag = 0; +} + +static char * +java_sprint_unicode (line, i) + struct java_line *line; + int i; +{ + static char buffer [10]; + if (line->unicode_escape_p [i] || line->line [i] > 128) + sprintf (buffer, "\\u%04x", line->line [i]); + else + { + buffer [0] = line->line [i]; + buffer [1] = '\0'; + } + return buffer; +} + +static unicode_t +java_sneak_unicode () +{ + return (ctxp->c_line->line [ctxp->c_line->current]); +} + +static void +java_unget_unicode (c) + unicode_t c; +{ + if (!ctxp->c_line->current) + fatal ("can't unget unicode - java_unget_unicode"); + ctxp->c_line->current--; + ctxp->c_line->char_col -= JAVA_COLUMN_DELTA (0); +} + +void +java_allocate_new_line () +{ + int i; + unicode_t ahead = (ctxp->c_line ? ctxp->c_line->ahead[0] : '\0'); + char ahead_escape_p = (ctxp->c_line ? + ctxp->c_line->unicode_escape_ahead_p : 0); + + if (ctxp->c_line && !ctxp->c_line->white_space_only) + { + if (ctxp->p_line) + { + free (ctxp->p_line->unicode_escape_p); + free (ctxp->p_line->line); + free (ctxp->p_line); + } + ctxp->p_line = ctxp->c_line; + ctxp->c_line = NULL; /* Reallocated */ + } + + if (!ctxp->c_line) + { + ctxp->c_line = (struct java_line *)malloc (sizeof (struct java_line)); + ctxp->c_line->max = JAVA_LINE_MAX; + ctxp->c_line->line = (unicode_t *)malloc + (sizeof (unicode_t)*ctxp->c_line->max); + ctxp->c_line->unicode_escape_p = + (char *)malloc (sizeof (char)*ctxp->c_line->max); + ctxp->c_line->white_space_only = 0; + } + + ctxp->c_line->line [0] = ctxp->c_line->size = 0; + ctxp->c_line->char_col = ctxp->c_line->current = 0; + if (ahead) + { + ctxp->c_line->line [ctxp->c_line->size] = ahead; + ctxp->c_line->unicode_escape_p [ctxp->c_line->size] = ahead_escape_p; + ctxp->c_line->size++; + } + ctxp->c_line->ahead [0] = 0; + ctxp->c_line->unicode_escape_ahead_p = 0; + ctxp->c_line->lineno = ++lineno; + ctxp->c_line->white_space_only = 1; +} + +static unicode_t +java_read_char () +{ + int c; + int c1, c2; + + if (ctxp->unget_utf8_value) + { + int to_return = ctxp->unget_utf8_value; + ctxp->unget_utf8_value = 0; + return (to_return); + } + + c = GETC (); + + if (c < 128) + return (unicode_t)c; + if (c == EOF) + return UEOF; + else + { + if (c & 0xe0 == 0xc0) + { + c1 = GETC (); + if (c1 & 0xc0 == 0x80) + return (unicode_t)(((c &0x1f) << 6) + (c1 & 0x3f)); + } + else if (c & 0xf0 == 0xe0) + { + c1 = GETC (); + if (c1 & 0xc0 == 0x80) + { + c2 = GETC (); + if (c2 & 0xc0 == 0x80) + return (unicode_t)(((c & 0xf) << 12) + + (( c1 & 0x3f) << 6) + (c2 & 0x3f)); + } + } + java_lex_error ("Bad utf8 encoding", 0); + } +} + +static void +java_store_unicode (l, c, unicode_escape_p) + struct java_line *l; + unicode_t c; + int unicode_escape_p; +{ + if (l->size == l->max) + { + l->max += JAVA_LINE_MAX; + l->line = (unicode_t *)realloc (l->line, sizeof (unicode_t)*l->max); + l->unicode_escape_p = (char *)realloc (l->unicode_escape_p, + sizeof (char)*l->max); + } + l->line [l->size] = c; + l->unicode_escape_p [l->size++] = unicode_escape_p; +} + +static unicode_t +java_read_unicode (term_context, unicode_escape_p) + int term_context; + int *unicode_escape_p; +{ + unicode_t c; + long i, base; + + c = java_read_char (); + *unicode_escape_p = 0; + + if (c != '\\') + return ((term_context ? c : + java_lineterminator (c) ? '\n' : (unicode_t)c)); + + /* Count the number of preceeding '\' */ + for (base = ftell (finput), i = base-2; c == '\\';) + { + fseek (finput, i--, SEEK_SET); + c = java_read_char (); /* Will fail if reading utf8 stream. FIXME */ + } + fseek (finput, base, SEEK_SET); + if ((base-i-3)%2 == 0) /* If odd number of \ seen */ + { + c = java_read_char (); + if (c == 'u') + { + unsigned short unicode = 0; + int shift = 12; + /* Next should be 4 hex digits, otherwise it's an error. + The hex value is converted into the unicode, pushed into + the Unicode stream. */ + for (shift = 12; shift >= 0; shift -= 4) + { + if ((c = java_read_char ()) == UEOF) + return UEOF; + if (c >= '0' && c <= '9') + unicode |= (unicode_t)((c-'0') << shift); + else if ((c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) + unicode |= (unicode_t)(10+(c | 0x20)-'a' << shift); + else + java_lex_error + ("Non hex digit in Unicode escape sequence", 0); + } + *unicode_escape_p = 1; + return (term_context ? unicode : + (java_lineterminator (c) ? '\n' : unicode)); + } + UNGETC (c); + } + return (unicode_t)'\\'; +} + +static unicode_t +java_get_unicode () +{ + /* It's time to read a line when... */ + if (!ctxp->c_line || ctxp->c_line->current == ctxp->c_line->size) + { + unicode_t c; + java_allocate_new_line (); + if (ctxp->c_line->line[0] != '\n') + for (;;) + { + int unicode_escape_p; + c = java_read_unicode (0, &unicode_escape_p); + java_store_unicode (ctxp->c_line, c, unicode_escape_p); + if (ctxp->c_line->white_space_only + && !JAVA_WHITE_SPACE_P (c) && c!='\n') + ctxp->c_line->white_space_only = 0; + if ((c == '\n') || (c == UEOF)) + break; + } + } + ctxp->c_line->char_col += JAVA_COLUMN_DELTA (0); + JAVA_LEX_CHAR (ctxp->c_line->line [ctxp->c_line->current]); + return ctxp->c_line->line [ctxp->c_line->current++]; +} + +static int +java_lineterminator (c) + unicode_t c; +{ + int unicode_escape_p; + if (c == '\n') /* CR */ + { + if ((c = java_read_unicode (1, &unicode_escape_p)) != '\r') + { + ctxp->c_line->ahead [0] = c; + ctxp->c_line->unicode_escape_ahead_p = unicode_escape_p; + } + return 1; + } + else if (c == '\r') /* LF */ + { + if ((c = java_read_unicode (1, &unicode_escape_p)) != '\n') + { + ctxp->c_line->ahead [0] = c; + ctxp->c_line->unicode_escape_ahead_p = unicode_escape_p; + } + return 1; + } + else + return 0; +} + +/* Parse the end of a C style comment */ +static void +java_parse_end_comment () +{ + unicode_t c; + + for (c = java_get_unicode ();; c = java_get_unicode ()) + { + switch (c) + { + case UEOF: + java_lex_error ("Comment not terminated at end of input", 0); + case '*': + switch (c = java_get_unicode ()) + { + case UEOF: + java_lex_error ("Comment not terminated at end of input", 0); + case '/': + return; + case '*': /* reparse only '*' */ + java_unget_unicode (c); + } + } + } +} + +/* This function to be used only by JAVA_ID_CHAR_P (), otherwise it + will return a wrong result. */ +static int +java_letter_or_digit_p (c) + unicode_t c; +{ + return _JAVA_LETTER_OR_DIGIT_P (c); +} + +static unicode_t +java_parse_escape_sequence () +{ + unicode_t char_lit; + unicode_t c; + + switch (c = java_get_unicode ()) + { + case 'b': + return (unicode_t)0x8; + case 't': + return (unicode_t)0x9; + case 'n': + return (unicode_t)0xa; + case 'f': + return (unicode_t)0xc; + case 'r': + return (unicode_t)0xd; + case '"': + return (unicode_t)0x22; + case '\'': + return (unicode_t)0x27; + case '\\': + return (unicode_t)0x5c; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + { + int octal_escape[3]; + int octal_escape_index = 0; + + for (; octal_escape_index < 3 && RANGE (c, '0', '9'); + c = java_get_unicode ()) + octal_escape [octal_escape_index++] = c; + + java_unget_unicode (c); + + if ((octal_escape_index == 3) && (octal_escape [0] > '3')) + { + java_lex_error ("Literal octal escape out of range", 0); + return JAVA_CHAR_ERROR; + } + else + { + int i, shift; + for (char_lit=0, i = 0, shift = 3*(octal_escape_index-1); + i < octal_escape_index; i++, shift -= 3) + char_lit |= (octal_escape [i] - '0') << shift; + + return (char_lit); + } + break; + } + case '\n': + return '\n'; /* ULT, caught latter as a specific error */ + default: + java_lex_error ("Illegal character in escape sequence", 0); + return JAVA_CHAR_ERROR; + } +} + +int +#ifdef JC1_LITE +yylex (java_lval) +#else +java_lex (java_lval) +#endif + YYSTYPE *java_lval; +{ + unicode_t c, first_unicode; + int line_terminator; + int ascii_index, all_ascii; + char *string; + + /* Translation of the Unicode escape in the raw stream of Unicode + characters. Takes care of line terminator. */ + step1: + /* Skip white spaces: SP, TAB and FF or ULT */ + for (c = java_get_unicode (); + c == '\n' || JAVA_WHITE_SPACE_P (c); c = java_get_unicode ()) + if (c == '\n') + { + ctxp->elc.line = ctxp->c_line->lineno; + ctxp->elc.col = ctxp->c_line->char_col-2; + } + + ctxp->elc.col = (ctxp->elc.col < 0 ? 0 : ctxp->elc.col); + + if (c == 0x1a) /* CTRL-Z */ + { + if ((c = java_get_unicode ()) == UEOF) + return 0; /* Ok here */ + else + java_unget_unicode (c); /* Caught latter at the end the function */ + } + /* Handle EOF here */ + if (c == UEOF) /* Should probably do something here... */ + return 0; + + /* Take care of eventual comments. */ + if (c == '/') + { + switch (c = java_get_unicode ()) + { + case '/': + for (c = java_get_unicode ();;c = java_get_unicode ()) + { + if (c == UEOF) + java_lex_error ("Comment not terminated at end of input", 0); + if (c == '\n') /* ULT */ + goto step1; + } + break; + + case '*': + if ((c = java_get_unicode ()) == '*') + { + if ((c = java_get_unicode ()) == '/') + goto step1; /* Empy documentation comment */ + + else + /* Parsing the documentation section. We're looking + for the @depracated pseudo keyword. the @deprecated + tag must be at the beginning of a doc comment line + (ignoring white space and any * character) */ + + { + int valid_tag = 0, seen_star; + + while (JAVA_WHITE_SPACE_P (c) || (c == '*') || c == '\n') + { + switch (c) + { + case '*': + seen_star = 1; + break; + case '\n': /* ULT */ + valid_tag = 1; + break; + default: + seen_star = 0; + } + c = java_get_unicode(); + } + + if (c == UEOF) + java_lex_error + ("Comment not terminated at end of input", 0); + + if (seen_star && (c == '/')) + goto step1; /* End of documentation */ + + if (valid_tag && (c == '@')) + { + char deprecated [10]; + int deprecated_index = 0; + + for (deprecated_index = 0, c = java_get_unicode (); + deprecated_index < 10 && c != UEOF; + c = java_get_unicode ()) + deprecated [deprecated_index++] = c; + + if (c == UEOF) + java_lex_error + ("Comment not terminated at end of input", 0); + + java_unget_unicode (c); + deprecated [deprecated_index] = '\0'; + if (!strcmp (deprecated, "deprecated")) + { + /* Set global flag to be checked by class. FIXME */ + warning ("deprecated implementation found"); + } + } + } + } + else + java_unget_unicode (c); + + java_parse_end_comment (); + goto step1; + break; + default: + java_unget_unicode (c); + c = '/'; + break; + } + } + + ctxp->elc.line = ctxp->c_line->lineno; + ctxp->elc.col = ctxp->c_line->char_col - JAVA_COLUMN_DELTA (-1); + if (ctxp->elc.col < 0) + fatal ("ctxp->elc.col < 0 - java_lex"); + + /* Numeric literals */ + if (JAVA_ASCII_DIGIT (c) || (c == '.')) + { + unicode_t peep; + /* This section of code is borrowed from gcc/c-lex.c */ +#define TOTAL_PARTS ((HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR) * 2 + 2) + int parts[TOTAL_PARTS]; + HOST_WIDE_INT high, low; + /* End borrowed section */ + char literal_token [256]; + int literal_index = 0, radix = 10, long_suffix = 0, overflow = 0, bytes; + int i; + int number_beginning = ctxp->c_line->current; + + /* We might have a . separator instead of a FP like .[0-9]* */ + if (c == '.') + { + unicode_t peep = java_sneak_unicode (); + + if (!JAVA_ASCII_DIGIT (peep)) + { + JAVA_LEX_SEP('.'); + BUILD_OPERATOR (DOT_TK); + } + } + + for (i = 0; i < TOTAL_PARTS; i++) + parts [i] = 0; + + if (c == '0') + { + c = java_get_unicode (); + if (c == 'x' || c == 'X') + { + radix = 16; + c = java_get_unicode (); + } + else if (JAVA_ASCII_DIGIT (c)) + radix = 8; + else if (c == '.') + { + /* Push the '.' back and prepare for a FP parsing... */ + java_unget_unicode (c); + c = '0'; + } + else + { + /* We have a zero literal: 0, 0{f,F}, 0{d,D} */ + JAVA_LEX_LIT ("0", 10); + switch (c) + { + case 'L': case 'l': + SET_LVAL_NODE_TYPE (integer_zero_node, long_type_node); + return (INT_LIT_TK); + case 'f': case 'F': + SET_LVAL_NODE_TYPE (build_real (float_type_node, dconst0), + float_type_node); + return (FP_LIT_TK); + case 'd': case 'D': + SET_LVAL_NODE_TYPE (build_real (double_type_node, dconst0), + double_type_node); + return (FP_LIT_TK); + default: + java_unget_unicode (c); + SET_LVAL_NODE_TYPE (integer_zero_node, int_type_node); + return (INT_LIT_TK); + } + } + } + /* Parse the first part of the literal, until we find something + which is not a number. */ + while ((radix == 10 && JAVA_ASCII_DIGIT (c)) || + (radix == 16 && JAVA_ASCII_HEXDIGIT (c)) || + (radix == 8 && JAVA_ASCII_OCTDIGIT (c))) + { + /* We store in a string (in case it turns out to be a FP) and in + PARTS if we have to process a integer literal. */ + int numeric = (RANGE (c, '0', '9') ? c-'0' : 10 +(c|0x20)-'a'); + int count; + + literal_token [literal_index++] = c; + /* This section of code if borrowed from gcc/c-lex.c */ + for (count = 0; count < TOTAL_PARTS; count++) + { + parts[count] *= radix; + if (count) + { + parts[count] += (parts[count-1] >> HOST_BITS_PER_CHAR); + parts[count-1] &= (1 << HOST_BITS_PER_CHAR) - 1; + } + else + parts[0] += numeric; + } + if (parts [TOTAL_PARTS-1] != 0) + overflow = 1; + /* End borrowed section. */ + c = java_get_unicode (); + } + + /* If we have something from the FP char set but not a digit, parse + a FP literal. */ + if (JAVA_ASCII_FPCHAR (c) && !JAVA_ASCII_DIGIT (c)) + { + int stage = 0; + int seen_digit = (literal_index ? 1 : 0); + int seen_exponent = 0; + int fflag = 0; /* 1 for {f,F}, 0 for {d,D}. FP literal are + double unless specified. */ + if (radix != 10) + java_lex_error ("Can't express non-decimal FP literal", 0); + + for (;;) + { + if (c == '.') + { + if (stage < 1) + { + stage = 1; + literal_token [literal_index++ ] = c; + c = java_get_unicode (); + } + else + java_lex_error ("Invalid character in FP literal", 0); + } + + if (c == 'e' || c == 'E') + { + if (stage < 2) + { + /* {E,e} must have seen at list a digit */ + if (!seen_digit) + java_lex_error ("Invalid FP literal", 0); + seen_digit = 0; + seen_exponent = 1; + stage = 2; + literal_token [literal_index++] = c; + c = java_get_unicode (); + } + else + java_lex_error ("Invalid character in FP literal", 0); + } + if ( c == 'f' || c == 'F' || c == 'd' || c == 'D') + { + fflag = ((c == 'd') || (c == 'D')) ? 0 : 1; + stage = 4; /* So we fall through */ + } + + if ((c=='-' || c =='+') && stage < 3) + { + stage = 3; + literal_token [literal_index++] = c; + c = java_get_unicode (); + } + + if ((stage == 0 && JAVA_ASCII_FPCHAR (c)) || + (stage == 1 && JAVA_ASCII_FPCHAR (c) && !(c == '.')) || + (stage == 2 && (JAVA_ASCII_DIGIT (c) || JAVA_FP_PM (c))) || + (stage == 3 && JAVA_ASCII_DIGIT (c))) + { + if (JAVA_ASCII_DIGIT (c)) + seen_digit = 1; + literal_token [literal_index++ ] = c; + c = java_get_unicode (); + } + else + { + jmp_buf handler; + REAL_VALUE_TYPE value; +#ifndef JC1_LITE + tree type = (fflag ? FLOAT_TYPE_NODE : DOUBLE_TYPE_NODE); +#endif + + if (stage != 4) /* Don't push back fF/dD */ + java_unget_unicode (c); + + /* An exponent (if any) must have seen a digit. */ + if (seen_exponent && !seen_digit) + java_lex_error ("Invalid FP literal", 0); + + literal_token [literal_index] = '\0'; + JAVA_LEX_LIT (literal_token, radix); + + if (setjmp (handler)) + { + JAVA_FLOAT_RANGE_ERROR ((fflag ? "float" : "double")); + value = DCONST0; + } + else + { + SET_FLOAT_HANDLER (handler); + SET_REAL_VALUE_ATOF + (value, REAL_VALUE_ATOF (literal_token, + TYPE_MODE (type))); + + if (REAL_VALUE_ISINF (value)) + JAVA_FLOAT_RANGE_ERROR ((fflag ? "float" : "double")); + + if (REAL_VALUE_ISNAN (value)) + JAVA_FLOAT_RANGE_ERROR ((fflag ? "float" : "double")); + + SET_LVAL_NODE_TYPE (build_real (type, value), type); + SET_FLOAT_HANDLER (NULL_PTR); + return FP_LIT_TK; + } + } + } + } /* JAVA_ASCCI_FPCHAR (c) */ + + /* Here we get back to converting the integral literal. */ + if (c == 'L' || c == 'l') + long_suffix = 1; + else if (radix == 16 && JAVA_ASCII_LETTER (c)) + java_lex_error ("Digit out of range in hexadecimal literal", 0); + else if (radix == 8 && JAVA_ASCII_DIGIT (c)) + java_lex_error ("Digit out of range in octal literal", 0); + else if (radix == 16 && !literal_index) + java_lex_error ("No digit specified for hexadecimal literal", 0); + else + java_unget_unicode (c); + +#ifdef JAVA_LEX_DEBUG + literal_token [literal_index] = '\0'; /* So JAVA_LEX_LIT is safe. */ + JAVA_LEX_LIT (literal_token, radix); +#endif + /* This section of code is borrowed from gcc/c-lex.c */ + if (!overflow) + { + bytes = GET_TYPE_PRECISION (long_type_node); + for (i = bytes; i < TOTAL_PARTS; i++) + if (parts [i]) + { + overflow = 1; + break; + } + } + high = low = 0; + for (i = 0; i < HOST_BITS_PER_WIDE_INT / HOST_BITS_PER_CHAR; i++) + { + high |= ((HOST_WIDE_INT) parts[i + (HOST_BITS_PER_WIDE_INT + / HOST_BITS_PER_CHAR)] + << (i * HOST_BITS_PER_CHAR)); + low |= (HOST_WIDE_INT) parts[i] << (i * HOST_BITS_PER_CHAR); + } + /* End borrowed section. */ + + /* Range checking */ + if (long_suffix) + { + /* 9223372036854775808L is valid if operand of a '-'. Otherwise + 9223372036854775807L is the biggest `long' literal that can be + expressed using a 10 radix. For other radixes, everything that + fits withing 64 bits is OK. */ + int hb = (high >> 31); + if (overflow || (hb && low && radix == 10) || + (hb && high & 0x7fffffff && radix == 10) || + (hb && !(high & 0x7fffffff) && !ctxp->minus_seen && radix == 10)) + JAVA_INTEGRAL_RANGE_ERROR ("Numeric overflow for `long' literal"); + } + else + { + /* 2147483648 is valid if operand of a '-'. Otherwise, + 2147483647 is the biggest `int' literal that can be + expressed using a 10 radix. For other radixes, everything + that fits within 32 bits is OK. */ + int hb = (low >> 31) & 0x1; + if (overflow || high || (hb && low & 0x7fffffff && radix == 10) || + (hb && !(low & 0x7fffffff) && !ctxp->minus_seen && radix == 10)) + JAVA_INTEGRAL_RANGE_ERROR ("Numeric overflow for `int' literal"); + } + ctxp->minus_seen = 0; + SET_LVAL_NODE_TYPE (build_int_2 (low, high), + (long_suffix ? long_type_node : int_type_node)); + return INT_LIT_TK; + } + + ctxp->minus_seen = 0; + /* Character literals */ + if (c == '\'') + { + unicode_t char_lit; + if ((c = java_get_unicode ()) == '\\') + char_lit = java_parse_escape_sequence (); + else + char_lit = c; + + c = java_get_unicode (); + + if ((c == '\n') || (c == UEOF)) + java_lex_error ("Character literal not terminated at end of line", 0); + if (c != '\'') + java_lex_error ("Syntax error in character literal", 0); + + if (c == JAVA_CHAR_ERROR) + char_lit = 0; /* We silently convert it to zero */ + + JAVA_LEX_CHAR_LIT (char_lit); + SET_LVAL_NODE_TYPE (build_int_2 (char_lit, 0), char_type_node); + return CHAR_LIT_TK; + } + + /* String literals */ + if (c == '"') + { + int no_error; + char *string; + + for (no_error = 1, c = java_get_unicode (); + c != '"' && c != '\n'; c = java_get_unicode ()) + { + if (c == '\\') + c = java_parse_escape_sequence (); + no_error &= (c != JAVA_CHAR_ERROR ? 1 : 0); + if (c) + java_unicode_2_utf8 (c); + } + if (c == '\n' || c == UEOF) /* ULT */ + { + lineno--; /* Refer to the line the terminator was seen */ + java_lex_error ("String not terminated at end of line.", 0); + lineno++; + } + + obstack_1grow (&temporary_obstack, '\0'); + string = obstack_finish (&temporary_obstack); + if (!no_error || (c != '"')) + *string = '\0'; /* Silently turns the string to an empty one */ + + JAVA_LEX_STR_LIT (string) + +#ifndef JC1_LITE + if (*string) + { + extern struct obstack *expression_obstack; + tree s = make_node (STRING_CST); + TREE_STRING_LENGTH (s) = strlen (string); + TREE_STRING_POINTER (s) = + obstack_alloc (expression_obstack, strlen (string)); + strcpy (TREE_STRING_POINTER (s), string); + java_lval->node = s; + } + else + java_lval->node = error_mark_node; +#endif + return STRING_LIT_TK; + + } + + /* Separator */ + switch (c) + { + case '(': + JAVA_LEX_SEP (c); + BUILD_OPERATOR (OP_TK); + case ')': + JAVA_LEX_SEP (c); + return CP_TK; + case '{': + JAVA_LEX_SEP (c); + if (ctxp->ccb_indent == 1) + ctxp->first_ccb_indent1 = lineno; + ctxp->ccb_indent++; + return OCB_TK; + case '}': + JAVA_LEX_SEP (c); + ctxp->ccb_indent--; + if (ctxp->ccb_indent == 1) + ctxp->last_ccb_indent1 = lineno; + return CCB_TK; + case '[': + JAVA_LEX_SEP (c); + BUILD_OPERATOR (OSB_TK); + case ']': + JAVA_LEX_SEP (c); + return CSB_TK; + case ';': + JAVA_LEX_SEP (c); + return SC_TK; + case ',': + JAVA_LEX_SEP (c); + return C_TK; + case '.': + JAVA_LEX_SEP (c); + BUILD_OPERATOR (DOT_TK); + /* return DOT_TK; */ + } + + /* Operators */ + switch (c) + { + case '=': + if ((c = java_get_unicode ()) == '=') + { + BUILD_OPERATOR (EQ_TK); + } + else + { + /* Equals is used in two different locations. In the + variable_declarator: rule, it has to be seen as '=' as opposed + to being seen as an ordinary assignment operator in + assignment_operators: rule. */ + java_unget_unicode (c); + BUILD_OPERATOR (ASSIGN_TK); + } + + case '>': + switch ((c = java_get_unicode ())) + { + case '=': + BUILD_OPERATOR (GTE_TK); + case '>': + switch ((c = java_get_unicode ())) + { + case '>': + if ((c = java_get_unicode ()) == '=') + { + BUILD_OPERATOR2 (ZRS_ASSIGN_TK); + } + else + { + java_unget_unicode (c); + BUILD_OPERATOR (ZRS_TK); + } + case '=': + BUILD_OPERATOR2 (SRS_ASSIGN_TK); + default: + java_unget_unicode (c); + BUILD_OPERATOR (SRS_TK); + } + default: + java_unget_unicode (c); + BUILD_OPERATOR (GT_TK); + } + + case '<': + switch ((c = java_get_unicode ())) + { + case '=': + BUILD_OPERATOR (LTE_TK); + case '<': + if ((c = java_get_unicode ()) == '=') + { + BUILD_OPERATOR2 (LS_ASSIGN_TK); + } + else + { + java_unget_unicode (c); + BUILD_OPERATOR (LS_TK); + } + default: + java_unget_unicode (c); + BUILD_OPERATOR (LT_TK); + } + + case '&': + switch ((c = java_get_unicode ())) + { + case '&': + BUILD_OPERATOR (BOOL_AND_TK); + case '=': + BUILD_OPERATOR2 (AND_ASSIGN_TK); + default: + java_unget_unicode (c); + BUILD_OPERATOR (AND_TK); + } + + case '|': + switch ((c = java_get_unicode ())) + { + case '|': + BUILD_OPERATOR (BOOL_OR_TK); + case '=': + BUILD_OPERATOR2 (OR_ASSIGN_TK); + default: + java_unget_unicode (c); + BUILD_OPERATOR (OR_TK); + } + + case '+': + switch ((c = java_get_unicode ())) + { + case '+': + BUILD_OPERATOR (INCR_TK); + case '=': + BUILD_OPERATOR2 (PLUS_ASSIGN_TK); + default: + java_unget_unicode (c); + BUILD_OPERATOR (PLUS_TK); + } + + case '-': + switch ((c = java_get_unicode ())) + { + case '-': + BUILD_OPERATOR (DECR_TK); + case '=': + BUILD_OPERATOR2 (MINUS_ASSIGN_TK); + default: + java_unget_unicode (c); + ctxp->minus_seen = 1; + BUILD_OPERATOR (MINUS_TK); + } + + case '*': + if ((c = java_get_unicode ()) == '=') + { + BUILD_OPERATOR2 (MULT_ASSIGN_TK); + } + else + { + java_unget_unicode (c); + BUILD_OPERATOR (MULT_TK); + } + + case '/': + if ((c = java_get_unicode ()) == '=') + { + BUILD_OPERATOR2 (DIV_ASSIGN_TK); + } + else + { + java_unget_unicode (c); + BUILD_OPERATOR (DIV_TK); + } + + case '^': + if ((c = java_get_unicode ()) == '=') + { + BUILD_OPERATOR2 (XOR_ASSIGN_TK); + } + else + { + java_unget_unicode (c); + BUILD_OPERATOR (XOR_TK); + } + + case '%': + if ((c = java_get_unicode ()) == '=') + { + BUILD_OPERATOR2 (REM_ASSIGN_TK); + } + else + { + java_unget_unicode (c); + BUILD_OPERATOR (REM_TK); + } + + case '!': + if ((c = java_get_unicode()) == '=') + { + BUILD_OPERATOR (NEQ_TK); + } + else + { + java_unget_unicode (c); + BUILD_OPERATOR (NEG_TK); + } + + case '?': + JAVA_LEX_OP ("?"); + BUILD_OPERATOR (REL_QM_TK); + case ':': + JAVA_LEX_OP (":"); + BUILD_OPERATOR (REL_CL_TK); + case '~': + BUILD_OPERATOR (NOT_TK); + } + + /* Keyword, boolean literal or null literal */ + for (first_unicode = c, all_ascii = 1, ascii_index = 0; + JAVA_ID_CHAR_P (c); c = java_get_unicode ()) + { + java_unicode_2_utf8 (c); + if (all_ascii && c >= 128) + all_ascii = 0; + ascii_index++; + } + + obstack_1grow (&temporary_obstack, '\0'); + string = obstack_finish (&temporary_obstack); + java_unget_unicode (c); + + /* If we have something all ascii, we consider a keyword, a boolean + literal, a null literal or an all ASCII identifier. Otherwise, + this is an identifier (possibly not respecting formation rule). */ + if (all_ascii) + { + struct java_keyword *kw; + if ((kw=java_keyword (string, ascii_index))) + { + JAVA_LEX_KW (string); + switch (kw->token) + { + case PUBLIC_TK: case PROTECTED_TK: case STATIC_TK: + case ABSTRACT_TK: case FINAL_TK: case NATIVE_TK: + case SYNCHRONIZED_TK: case TRANSIENT_TK: case VOLATILE_TK: + case PRIVATE_TK: + SET_MODIFIER_CTX (kw->token); + return MODIFIER_TK; + case FLOAT_TK: + SET_LVAL_NODE (float_type_node); + return FP_TK; + case DOUBLE_TK: + SET_LVAL_NODE (double_type_node); + return FP_TK; + case BOOLEAN_TK: + SET_LVAL_NODE (boolean_type_node); + return BOOLEAN_TK; + case BYTE_TK: + SET_LVAL_NODE (byte_type_node); + return INTEGRAL_TK; + case SHORT_TK: + SET_LVAL_NODE (short_type_node); + return INTEGRAL_TK; + case INT_TK: + SET_LVAL_NODE (int_type_node); + return INTEGRAL_TK; + case LONG_TK: + SET_LVAL_NODE (long_type_node); + return INTEGRAL_TK; + case CHAR_TK: + SET_LVAL_NODE (char_type_node); + return INTEGRAL_TK; + + /* Keyword based literals */ + case TRUE_TK: + case FALSE_TK: + SET_LVAL_NODE ((kw->token == TRUE_TK ? + boolean_true_node : boolean_false_node)); + return BOOL_LIT_TK; + case NULL_TK: + SET_LVAL_NODE (null_pointer_node); + return NULL_TK; + + /* We build an operator for SUPER, so we can keep its position */ + case SUPER_TK: + case THIS_TK: + case RETURN_TK: + case BREAK_TK: + case CONTINUE_TK: + BUILD_OPERATOR (kw->token); + + default: + return kw->token; + } + } + } + + /* We may have and ID here */ + if (JAVA_ID_CHAR_P(first_unicode) && !JAVA_DIGIT_P (first_unicode)) + { + JAVA_LEX_ID (string); + java_lval->node = BUILD_ID_WFL (GET_IDENTIFIER (string)); + return ID_TK; + } + + /* Everything else is an invalid character in the input */ + { + char lex_error_buffer [128]; + sprintf (lex_error_buffer, "Invalid character '%s' in input", + java_sprint_unicode (ctxp->c_line, ctxp->c_line->current)); + java_lex_error (lex_error_buffer, 1); + } + return 0; +} + +static void +java_unicode_2_utf8 (unicode) + unicode_t unicode; +{ + if (RANGE (unicode, 0x01, 0x7f)) + obstack_1grow (&temporary_obstack, (char)unicode); + else if (RANGE (unicode, 0x80, 0x7ff) || unicode == 0) + { + obstack_1grow (&temporary_obstack, + (unsigned char)(0xc0 | ((0x7c0 & unicode) >> 6))); + obstack_1grow (&temporary_obstack, + (unsigned char)(0x80 | (unicode & 0x3f))); + } + else /* Range 0x800-0xffff */ + { + obstack_1grow (&temporary_obstack, + (unsigned char)(0xe0 | (unicode & 0xf000) >> 12)); + obstack_1grow (&temporary_obstack, + (unsigned char)(0x80 | (unicode & 0x0fc0) >> 6)); + obstack_1grow (&temporary_obstack, + (unsigned char)(0x80 | (unicode & 0x003f) >> 12)); + } +} + +#ifndef JC1_LITE +static tree +build_wfl_node (node) + tree node; +{ + return build_expr_wfl (node, ctxp->filename, ctxp->elc.line, ctxp->elc.col); +} +#endif + +static void +java_lex_error (msg, forward) + char *msg; + int forward; +{ +#ifndef JC1_LITE + ctxp->elc.line = ctxp->c_line->lineno; + ctxp->elc.col = ctxp->c_line->char_col-1+forward; + + /* Might be caught in the middle of some error report */ + ctxp->java_error_flag = 0; + java_error (NULL); + java_error (msg); +#endif +} + +static int +java_is_eol (fp, c) + FILE *fp; + int c; +{ + int next; + switch (c) + { + case '\n': + next = getc (fp); + if (next != '\r' && next != EOF) + ungetc (next, fp); + return 1; + case '\r': + return 1; + default: + return 0; + } +} + +char * +java_get_line_col (filename, line, col) + char *filename; + int line, col; +{ +#ifdef JC1_LITE + return 0; +#else + /* Dumb implementation. Doesn't try to cache or optimize things. */ + /* First line of the file is line 1, first column is 1 */ + + /* COL <= 0 means, at the CR/LF in LINE */ + + FILE *fp; + int c, ccol, cline = 1; + int current_line_col = 0; + + if (!(fp = fopen (filename, "r"))) + fatal ("Can't open file - java_display_line_col"); + + while (cline != line) + { + c = getc (fp); + if (c < 0) + { + static char msg[] = "<>"; + obstack_grow (&temporary_obstack, msg, sizeof(msg)-1); + goto have_line; + } + if (java_is_eol (fp, c)) + cline++; + } + + /* Gather the chars of the current line in a buffer */ + for (;;) + { + c = getc (fp); + if (c < 0 || java_is_eol (fp, c)) + break; + obstack_1grow (&temporary_obstack, c); + current_line_col++; + } + have_line: + + obstack_1grow (&temporary_obstack, '\n'); + + if (col < 0) + col = current_line_col; + + /* Place the '^' a the right position */ + for (ccol = 1; ccol <= col; ccol++) + obstack_1grow (&temporary_obstack, ' '); + obstack_grow0 (&temporary_obstack, "^", 1); + + fclose (fp); + return obstack_finish (&temporary_obstack); +#endif +} diff --git a/gcc/java/lex.h b/gcc/java/lex.h new file mode 100644 index 00000000000..9116e42fbe0 --- /dev/null +++ b/gcc/java/lex.h @@ -0,0 +1,512 @@ +/* Language lexer definitions for the GNU compiler for the Java(TM) language. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +#ifndef JV_LEX_H +#define JV_LEX_H + +/* Extern global variables declarations */ +extern FILE *finput; +extern int lineno; +extern char *classpath; + +/* A Unicode character, as read from the input file */ +typedef unsigned short unicode_t; + +/* Function declaration */ +static int java_lineterminator (); +static char *java_sprint_unicode (); +static void java_unicode_2_utf8 (); +static void java_lex_error (); +static void java_store_unicode (); + +/* Debug macro to print-out what we match */ +#ifdef JAVA_LEX_DEBUG +#ifdef JAVA_LEX_DEBUG_CHAR +#define JAVA_LEX_CHAR(c) printf ("java_lex:%d: char '%c'.%d\n", \ + lineno, (c < 128 ? c : '.'), c); +#else +#define JAVA_LEX_CHAR(c) +#endif +#define JAVA_LEX_KW(c) printf ("java_lex:%d: keyword: '%s'\n", lineno,c) +#define JAVA_LEX_ID(s) printf ("java_lex:%d: ID: '%s'\n", \ + lineno, \ + (all_ascii ? s : "")) +#define JAVA_LEX_LIT(s, r) printf ("java_lex:%d: literal '%s'_%d\n", \ + lineno, s, r) +#define JAVA_LEX_CHAR_LIT(s) printf ("java_lex:%d: literal '%d'\n", lineno, s) +#define JAVA_LEX_STR_LIT(s) { \ + int i; \ + printf ("java_lex:%d: literal '%s'\n", \ + lineno, s); \ + } +#define JAVA_LEX_SEP(c) printf ("java_lex:%d: separator '%c'\n",lineno,c) +#define JAVA_LEX_OP(c) printf ("java_lex:%d: operator '%s'\n", lineno,c) +#else +#define JAVA_LEX_CHAR(c) +#define JAVA_LEX_KW(c) +#define JAVA_LEX_ID(s) +#define JAVA_LEX_LIT(s,r) +#define JAVA_LEX_CHAR_LIT(s) +#define JAVA_LEX_STR_LIT(s) +#define JAVA_LEX_SEP(c) +#define JAVA_LEX_OP(s) +#endif + +/* Line information containers */ +struct java_line { + unicode_t *line; /* The line's unicode */ + char *unicode_escape_p; /* The maching char was a unicode escape */ + unicode_t ahead[1]; /* Character ahead */ + char unicode_escape_ahead_p; /* Character ahead is a unicode escape */ + int max; /* buffer's max size */ + int size; /* number of unicodes */ + int current; /* Current position, unicode based */ + int char_col; /* Current position, input char based */ + int lineno; /* Its line number */ + int white_space_only; /* If it contains only white spaces */ +}; +#define JAVA_COLUMN_DELTA(p) \ + (ctxp->c_line->unicode_escape_p [ctxp->c_line->current+(p)] ? 6 : \ + (ctxp->c_line->line [ctxp->c_line->current+(p)] == '\t' ? 8 : 1)) + +struct java_error { + struct java_line *line; + int error; +}; + +typedef struct _java_lc { + int line; + int col; +} java_lc; + + +#define JAVA_LINE_MAX 80 + +/* Macro to read and unread chars */ +#define UNGETC(c) ctxp->unget_utf8_value = (c); +#define GETC() getc(finput) + +/* Build a location compound integer */ +#define BUILD_LOCATION() ((ctxp->elc.line << 12) | (ctxp->elc.col & 0xfff)) + +/* Those macros are defined differently if we compile jc1-lite + (JC1_LITE defined) or jc1. */ +#ifdef JC1_LITE + +#define DCONST0 0 +#define HOST_WIDE_INT long +#define HOST_BITS_PER_WIDE_INT 64 +#define HOST_BITS_PER_CHAR 8 +#define REAL_VALUE_TYPE int +#define SET_FLOAT_HANDLER(H) +#define GET_IDENTIFIER(S) xstrdup ((S)) +#define REAL_VALUE_ATOF(LIT,MODE) 0 +#define REAL_VALUE_ISINF(VALUE) 0 +#define REAL_VALUE_ISNAN(VALUE) 0 +#define SET_REAL_VALUE_ATOF(TARGET,SOURCE) +#define FLOAT_TYPE_NODE 0 +#define DOUBLE_TYPE_NODE 0 +#define SET_MODIFIER_CTX(TOKEN) java_lval->value = (TOKEN) +#define GET_TYPE_PRECISION(NODE) 4 +#define BUILD_OPERATOR(TOKEN) return TOKEN +#define BUILD_OPERATOR2(TOKEN) return TOKEN +#define SET_LVAL_NODE(NODE) +#define SET_LVAL_NODE_TYPE(NODE, TYPE) +#define BUILD_ID_WFL(EXP) (EXP) +#define JAVA_FLOAT_RANGE_ERROR(S) {} +#define JAVA_INTEGRAL_RANGE_ERROR(S) {} + +#else + +static tree build_wfl_node (); +#define SET_FLOAT_HANDLER(H) set_float_handler ((H)) +#define DCONST0 dconst0 +#define GET_IDENTIFIER(S) get_identifier ((S)) +#define SET_REAL_VALUE_ATOF(TARGET,SOURCE) (TARGET) = (SOURCE) +#define FLOAT_TYPE_NODE float_type_node +#define DOUBLE_TYPE_NODE double_type_node +/* Set modifier_ctx according to TOKEN */ +#define SET_MODIFIER_CTX(TOKEN) \ + { \ + ctxp->modifier_ctx [(TOKEN)-PUBLIC_TK] = build_wfl_node (NULL_TREE); \ + java_lval->value = (TOKEN)-PUBLIC_TK; \ + } +/* Type precision for long */ +#define GET_TYPE_PRECISION(NODE) TYPE_PRECISION (long_type_node) / 8; +/* Build an operator tree node and return TOKEN */ +#define BUILD_OPERATOR(TOKEN) \ + { \ + java_lval->operator.token = (TOKEN); \ + java_lval->operator.location = BUILD_LOCATION(); \ + return (TOKEN); \ + } + +/* Build an operator tree node but return ASSIGN_ANY_TK */ +#define BUILD_OPERATOR2(TOKEN) \ + { \ + java_lval->operator.token = (TOKEN); \ + java_lval->operator.location = BUILD_LOCATION(); \ + return ASSIGN_ANY_TK; \ + } +/* Set java_lval->node and TREE_TYPE(java_lval->node) in macros */ +#define SET_LVAL_NODE(NODE) java_lval->node = (NODE) +#define SET_LVAL_NODE_TYPE(NODE,TYPE) \ + { \ + java_lval->node = (NODE); \ + TREE_TYPE (java_lval->node) = (TYPE); \ + } +/* Wrap identifier around a wfl */ +#define BUILD_ID_WFL(EXP) build_wfl_node ((EXP)) +/* Special ways to report error on numeric literals */ +#define JAVA_FLOAT_RANGE_ERROR(m) \ + { \ + char msg [1024]; \ + int i = ctxp->c_line->current; \ + ctxp->c_line->current = number_beginning; \ + sprintf (msg, "Floating pointer literal exceeds range of `%s'", (m)); \ + java_lex_error (msg, 0); \ + ctxp->c_line->current = i; \ + value = dconst0; \ + } +#define JAVA_INTEGRAL_RANGE_ERROR(m) \ + { \ + int i = ctxp->c_line->current; \ + ctxp->c_line->current = number_beginning; \ + java_lex_error (m, 0); \ + ctxp->c_line->current = i; \ + } + +#endif /* Definitions for jc1 compilation only */ + +/* Macros to decode character ranges */ +#define RANGE(c, l, h) (((c) >= l && (c) <= h)) +#define JAVA_WHITE_SPACE_P(c) (c == ' ' || c == '\t' || c == '\f') +#define JAVA_ID_CHAR_P(c) ((c < 128 && (RANGE (c, 'A', 'Z') || \ + RANGE (c, 'a', 'z') || \ + RANGE (c, '0', '9') || \ + c == '_' || \ + c == '$')) || \ + (c > 127 && java_letter_or_digit_p (c))) +#define JAVA_ASCII_DIGIT(c) RANGE(c,'0', '9') +#define JAVA_ASCII_OCTDIGIT(c) RANGE(c,'0', '7') +#define JAVA_ASCII_HEXDIGIT(c) (RANGE(c,'0', '9') || \ + RANGE(c,'a', 'f') || \ + RANGE(c,'A', 'F')) +#define JAVA_ASCII_FPCHAR(c) (RANGE(c,'d', 'f') || RANGE(c,'D', 'F') || \ + c == '.' || JAVA_ASCII_DIGIT (c)) +#define JAVA_FP_SUFFIX(c) (c == 'D' || c == 'd' || c == 'f' || c == 'F') +#define JAVA_FP_EXP(c) (c == 'E' || c == 'F') +#define JAVA_FP_PM(c) (c == '-' || c == '+') +#define JAVA_ASCII_LETTER(c) (RANGE(c,'a', 'z') || RANGE(c,'A', 'Z')) +#define JAVA_DIGIT_P(c) \ + (RANGE (c, 0x030, 0x039) || /* ISO-Latin-1 (and ASCII) digits ('0'-'9') */ \ + RANGE (c, 0x660, 0x669) || /* Arabic-Indic digits */ \ + RANGE (c, 0x6F0, 0x6F9) || /* Eastern Arabic-Indic digits */ \ + RANGE (c, 0x966, 0x96F) || /* Devanagari digits */ \ + RANGE (c, 0x9E6, 0x9EF) || /* Bengali digits */ \ + RANGE (c, 0xA66, 0xA6F) || /* Gurmukhi digits */ \ + RANGE (c, 0xAE6, 0xAEF) || /* Gujarati digits */ \ + RANGE (c, 0xB66, 0xB6F) || /* Oriya digits */ \ + RANGE (c, 0xBE7, 0xBEF) || /* Tamil digits */ \ + RANGE (c, 0xC66, 0xC6F) || /* Telugu digits */ \ + RANGE (c, 0xCE6, 0xCEF) || /* Kannada digits */ \ + RANGE (c, 0xD66, 0xD6F) || /* Malayalam digits */ \ + RANGE (c, 0xE50, 0xE59) || /* Thai digits */ \ + RANGE (c, 0xED0, 0xED9)) /* Lao digits */ + +/* This is not to be used as a stand alone macro. Use JAVA_ID_CHAR_P() + or the forcoming JAVA_LETTER_OR_DIGIT_P() instead. + It need to be split by region. FIXME. */ +#define _JAVA_LETTER_OR_DIGIT_P(c) \ + (RANGE (c, 0x00C0, 0x00D6) || \ + RANGE (c, 0x00D8, 0x00F6) || \ + RANGE (c, 0x00F8, 0x01F5) || \ + RANGE (c, 0x01FA, 0x0217) || \ + RANGE (c, 0x0250, 0x02A8) || \ + RANGE (c, 0x02B0, 0x02DE) || \ + RANGE (c, 0x02E0, 0x02E9) || \ + RANGE (c, 0x0300, 0x0345) || \ + RANGE (c, 0x0360, 0x0361) || \ + RANGE (c, 0x0374, 0x0375) || \ + c == 0x037A || \ + c == 0x037E || \ + RANGE (c, 0x0384, 0x038A) || \ + c == 0x038C || \ + c == 0x038E || \ + RANGE (c, 0x038F, 0x03A1) || \ + RANGE (c, 0x03A3, 0x03CE) || \ + RANGE (c, 0x03D0, 0x03D6) || \ + RANGE (c, 0x03DA, 0x03E2) || \ + c == 0x03DA || \ + c == 0x03DC || \ + c == 0x03DE || \ + c == 0x03E0 || \ + RANGE (c, 0x03E2, 0x03F3) || \ + RANGE (c, 0x0401, 0x040C) || \ + RANGE (c, 0x040E, 0x044F) || \ + RANGE (c, 0x0451, 0x045C) || \ + RANGE (c, 0x045E, 0x0486) || \ + RANGE (c, 0x0490, 0x04C4) || \ + RANGE (c, 0x04C7, 0x04C8) || \ + RANGE (c, 0x04CB, 0x04CC) || \ + RANGE (c, 0x04D0, 0x04EB) || \ + RANGE (c, 0x04EE, 0x04F5) || \ + RANGE (c, 0x04F8, 0x04F9) || \ + RANGE (c, 0x0531, 0x0556) || \ + RANGE (c, 0x0559, 0x055F) || \ + RANGE (c, 0x0561, 0x0587) || \ + c == 0x0589 || \ + RANGE (c, 0x05B0, 0x05B9) || \ + RANGE (c, 0x05BB, 0x05C3) || \ + RANGE (c, 0x05D0, 0x05EA) || \ + RANGE (c, 0x05F0, 0x05F4) || \ + c == 0x060C || \ + c == 0x061B || \ + c == 0x061F || \ + c == 0x0621 || \ + RANGE (c, 0x0622, 0x063A) || \ + RANGE (c, 0x0640, 0x0652) || \ + RANGE (c, 0x0660, 0x066D) || \ + RANGE (c, 0x0670, 0x06B7) || \ + RANGE (c, 0x06BA, 0x06BE) || \ + RANGE (c, 0x06C0, 0x06CE) || \ + RANGE (c, 0x06D0, 0x06ED) || \ + RANGE (c, 0x06F0, 0x06F9) || \ + RANGE (c, 0x0901, 0x0903) || \ + RANGE (c, 0x0905, 0x0939) || \ + RANGE (c, 0x093C, 0x094D) || \ + RANGE (c, 0x0950, 0x0954) || \ + RANGE (c, 0x0958, 0x0970) || \ + RANGE (c, 0x0981, 0x0983) || \ + RANGE (c, 0x0985, 0x098C) || \ + RANGE (c, 0x098F, 0x0990) || \ + RANGE (c, 0x0993, 0x09A8) || \ + RANGE (c, 0x09AA, 0x09B0) || \ + c == 0x09B2 || \ + RANGE (c, 0x09B6, 0x09B9) || \ + c == 0x09BC || \ + c == 0x09BE || \ + RANGE (c, 0x09BF, 0x09C4) || \ + RANGE (c, 0x09C7, 0x09C8) || \ + RANGE (c, 0x09CB, 0x09CD) || \ + c == 0x09D7 || \ + RANGE (c, 0x09DC, 0x09DD) || \ + RANGE (c, 0x09DF, 0x09E3) || \ + RANGE (c, 0x09E6, 0x09FA) || \ + c == 0x0A02 || \ + RANGE (c, 0x0A05, 0x0A0A) || \ + RANGE (c, 0x0A0F, 0x0A10) || \ + RANGE (c, 0x0A13, 0x0A28) || \ + RANGE (c, 0x0A2A, 0x0A30) || \ + RANGE (c, 0x0A32, 0x0A33) || \ + RANGE (c, 0x0A35, 0x0A36) || \ + RANGE (c, 0x0A38, 0x0A39) || \ + c == 0x0A3C || \ + c == 0x0A3E || \ + RANGE (c, 0x0A3F, 0x0A42) || \ + RANGE (c, 0x0A47, 0x0A48) || \ + RANGE (c, 0x0A4B, 0x0A4D) || \ + RANGE (c, 0x0A59, 0x0A5C) || \ + c == 0x0A5E || \ + RANGE (c, 0x0A66, 0x0A74) || \ + RANGE (c, 0x0A81, 0x0A83) || \ + RANGE (c, 0x0A85, 0x0A8B) || \ + c == 0x0A8D || \ + c == 0x0A8F || \ + RANGE (c, 0x0A90, 0x0A91) || \ + RANGE (c, 0x0A93, 0x0AA8) || \ + RANGE (c, 0x0AAA, 0x0AB0) || \ + RANGE (c, 0x0AB2, 0x0AB3) || \ + RANGE (c, 0x0AB5, 0x0AB9) || \ + RANGE (c, 0x0ABC, 0x0AC5) || \ + RANGE (c, 0x0AC7, 0x0AC9) || \ + RANGE (c, 0x0ACB, 0x0ACD) || \ + c == 0x0AD0 || \ + c == 0x0AE0 || \ + RANGE (c, 0x0AE6, 0x0AEF) || \ + RANGE (c, 0x0B01, 0x0B03) || \ + RANGE (c, 0x0B05, 0x0B0C) || \ + RANGE (c, 0x0B0F, 0x0B10) || \ + RANGE (c, 0x0B13, 0x0B28) || \ + RANGE (c, 0x0B2A, 0x0B30) || \ + RANGE (c, 0x0B32, 0x0B33) || \ + RANGE (c, 0x0B36, 0x0B39) || \ + RANGE (c, 0x0B3C, 0x0B43) || \ + RANGE (c, 0x0B47, 0x0B48) || \ + RANGE (c, 0x0B4B, 0x0B4D) || \ + RANGE (c, 0x0B56, 0x0B57) || \ + RANGE (c, 0x0B5C, 0x0B5D) || \ + RANGE (c, 0x0B5F, 0x0B61) || \ + RANGE (c, 0x0B66, 0x0B70) || \ + RANGE (c, 0x0B82, 0x0B83) || \ + RANGE (c, 0x0B85, 0x0B8A) || \ + RANGE (c, 0x0B8E, 0x0B90) || \ + RANGE (c, 0x0B92, 0x0B95) || \ + RANGE (c, 0x0B99, 0x0B9A) || \ + c == 0x0B9C || \ + c == 0x0B9E || \ + c == 0x0B9F || \ + RANGE (c, 0x0BA3, 0x0BA4) || \ + RANGE (c, 0x0BA8, 0x0BAA) || \ + RANGE (c, 0x0BAE, 0x0BB5) || \ + RANGE (c, 0x0BB7, 0x0BB9) || \ + RANGE (c, 0x0BBE, 0x0BC2) || \ + RANGE (c, 0x0BC6, 0x0BC8) || \ + RANGE (c, 0x0BCA, 0x0BCD) || \ + c == 0x0BD7 || \ + RANGE (c, 0x0BE7, 0x0BF2) || \ + RANGE (c, 0x0C01, 0x0C03) || \ + RANGE (c, 0x0C05, 0x0C0C) || \ + RANGE (c, 0x0C0E, 0x0C10) || \ + RANGE (c, 0x0C12, 0x0C28) || \ + RANGE (c, 0x0C2A, 0x0C33) || \ + RANGE (c, 0x0C35, 0x0C39) || \ + RANGE (c, 0x0C3E, 0x0C44) || \ + RANGE (c, 0x0C46, 0x0C48) || \ + RANGE (c, 0x0C4A, 0x0C4D) || \ + RANGE (c, 0x0C55, 0x0C56) || \ + RANGE (c, 0x0C60, 0x0C61) || \ + RANGE (c, 0x0C66, 0x0C6F) || \ + RANGE (c, 0x0C82, 0x0C83) || \ + RANGE (c, 0x0C85, 0x0C8C) || \ + RANGE (c, 0x0C8E, 0x0C90) || \ + RANGE (c, 0x0C92, 0x0CA8) || \ + RANGE (c, 0x0CAA, 0x0CB3) || \ + RANGE (c, 0x0CB5, 0x0CB9) || \ + RANGE (c, 0x0CBE, 0x0CC4) || \ + RANGE (c, 0x0CC6, 0x0CC8) || \ + RANGE (c, 0x0CCA, 0x0CCD) || \ + RANGE (c, 0x0CD5, 0x0CD6) || \ + c == 0x0CDE || \ + c == 0x0CE0 || \ + c == 0x0CE1 || \ + RANGE (c, 0x0CE6, 0x0CEF) || \ + RANGE (c, 0x0D02, 0x0D03) || \ + RANGE (c, 0x0D05, 0x0D0C) || \ + RANGE (c, 0x0D0E, 0x0D10) || \ + RANGE (c, 0x0D12, 0x0D28) || \ + RANGE (c, 0x0D2A, 0x0D39) || \ + RANGE (c, 0x0D3E, 0x0D43) || \ + RANGE (c, 0x0D46, 0x0D48) || \ + RANGE (c, 0x0D4A, 0x0D4D) || \ + c == 0x0D57 || \ + RANGE (c, 0x0D60, 0x0D61) || \ + RANGE (c, 0x0D66, 0x0D6F) || \ + RANGE (c, 0x0E01, 0x0E3A) || \ + RANGE (c, 0x0E3F, 0x0E5B) || \ + RANGE (c, 0x0E81, 0x0E82) || \ + c == 0x0E84 || \ + RANGE (c, 0x0E87, 0x0E88) || \ + c == 0x0E8A || \ + c == 0x0E8D || \ + RANGE (c, 0x0E94, 0x0E97) || \ + RANGE (c, 0x0E99, 0x0E9F) || \ + RANGE (c, 0x0EA1, 0x0EA3) || \ + c == 0x0EA5 || \ + c == 0x0EA7 || \ + RANGE (c, 0x0EAA, 0x0EAB) || \ + RANGE (c, 0x0EAD, 0x0EB9) || \ + RANGE (c, 0x0EBB, 0x0EBD) || \ + RANGE (c, 0x0EC0, 0x0EC4) || \ + c == 0x0EC6 || \ + c == 0x0EC8 || \ + RANGE (c, 0x0EC9, 0x0ECD) || \ + RANGE (c, 0x0ED0, 0x0ED9) || \ + RANGE (c, 0x0EDC, 0x0EDD) || \ + RANGE (c, 0x10A0, 0x10C5) || \ + RANGE (c, 0x10D0, 0x10F6) || \ + c == 0x10FB || \ + RANGE (c, 0x1100, 0x1159) || \ + RANGE (c, 0x115F, 0x11A2) || \ + RANGE (c, 0x11A8, 0x11F9) || \ + RANGE (c, 0x1E00, 0x1E9A) || \ + RANGE (c, 0x1EA0, 0x1EF9) || \ + RANGE (c, 0x1F00, 0x1F15) || \ + RANGE (c, 0x1F18, 0x1F1D) || \ + RANGE (c, 0x1F20, 0x1F45) || \ + RANGE (c, 0x1F48, 0x1F4D) || \ + RANGE (c, 0x1F50, 0x1F57) || \ + c == 0x1F59 || \ + c == 0x1F5B || \ + c == 0x1F5D || \ + RANGE (c, 0x1F5F, 0x1F7D) || \ + RANGE (c, 0x1F80, 0x1FB4) || \ + RANGE (c, 0x1FB6, 0x1FC4) || \ + RANGE (c, 0x1FC6, 0x1FD3) || \ + RANGE (c, 0x1FD6, 0x1FDB) || \ + RANGE (c, 0x1FDD, 0x1FEF) || \ + RANGE (c, 0x1FF2, 0x1FF4) || \ + RANGE (c, 0x1FF6, 0x1FFE) || \ + RANGE (c, 0x3041, 0x3094) || \ + RANGE (c, 0x3099, 0x309E) || \ + RANGE (c, 0x30A1, 0x30FE) || \ + RANGE (c, 0x3105, 0x312C) || \ + RANGE (c, 0x3131, 0x318E) || \ + RANGE (c, 0x3190, 0x319F) || \ + RANGE (c, 0x3200, 0x321C) || \ + RANGE (c, 0x3220, 0x3243) || \ + RANGE (c, 0x3260, 0x327B) || \ + RANGE (c, 0x327F, 0x32B0) || \ + RANGE (c, 0x32C0, 0x32CB) || \ + RANGE (c, 0x32D0, 0x32FE) || \ + RANGE (c, 0x3300, 0x3376) || \ + RANGE (c, 0x337B, 0x33DD) || \ + RANGE (c, 0x33E0, 0x33FE) || \ + RANGE (c, 0x3400, 0x9FA5) || \ + RANGE (c, 0xF900, 0xFA2D) || \ + RANGE (c, 0xFB00, 0xFB06) || \ + RANGE (c, 0xFB13, 0xFB17) || \ + RANGE (c, 0xFB1E, 0xFB36) || \ + RANGE (c, 0xFB38, 0xFB3C) || \ + c == 0xFB3E || \ + c == 0xFB40 || \ + c == 0xFB41 || \ + c == 0xFB43 || \ + c == 0xFB44 || \ + c == 0xFB46 || \ + RANGE (c, 0xFB47, 0xFBB1) || \ + RANGE (c, 0xFBD3, 0xFD3F) || \ + RANGE (c, 0xFD50, 0xFD8F) || \ + RANGE (c, 0xFD92, 0xFDC7) || \ + RANGE (c, 0xFDF0, 0xFDFB) || \ + RANGE (c, 0xFE70, 0xFE72) || \ + c == 0xFE74 || \ + c == 0xFE76 || \ + RANGE (c, 0xFE77, 0xFEFC) || \ + RANGE (c, 0xFF10, 0xFF19) || \ + RANGE (c, 0xFF21, 0xFF3A) || \ + RANGE (c, 0xFF41, 0xFF5A) || \ + RANGE (c, 0xFF66, 0xFFBE) || \ + RANGE (c, 0xFFC2, 0xFFC7) || \ + RANGE (c, 0xFFCA, 0xFFCF) || \ + RANGE (c, 0xFFD2, 0xFFD7) || \ + RANGE (c, 0xFFDA, 0xFFDC)) + +/* Constants */ +#define JAVA_CHAR_ERROR 0xFFC1 /* This is an illegal unicode!?! FIXME */ +#define JAVA_READ_BUFFER 256 +#define UEOF (unicode_t)0xffff + +#endif diff --git a/gcc/java/mangle.c b/gcc/java/mangle.c new file mode 100644 index 00000000000..f303c926a08 --- /dev/null +++ b/gcc/java/mangle.c @@ -0,0 +1,163 @@ +/* Functions related to mangling class names for the GNU compiler + for the Java(TM) language. + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Written by Per Bothner */ + +#include +#include +#include "config.h" +#include "jcf.h" +#include "obstack.h" + +/* Assuming (NAME, LEN) is a Utf8-encoding string, calculate + the length of the string as mangled (a la g++) including Unicode escapes. + If no escapes are needed, return 0. */ + +int +unicode_mangling_length (name, len) + char *name; + int len; +{ + unsigned char *ptr; + unsigned char *limit = (unsigned char *)name + len; + int need_escapes = 0; + int num_chars = 0; + int underscores = 0; + for (ptr = (unsigned char *) name; ptr < limit; ) + { + int ch = UTF8_GET(ptr, limit); + if (ch < 0) + error ("internal error - invalid Utf8 name"); + if (ch >= '0' && ch <= '9') + need_escapes += num_chars == 0; + else if (ch == '_') + underscores++; + else if ((ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z')) + need_escapes++; + num_chars++; + } + if (need_escapes) + return num_chars + 4 * (need_escapes + underscores); + else + return 0; +} + +/* Assuming (NAME, LEN) is a Utf8-encoding string, emit the string + appropriately mangled (with Unicode escapes) to OBSTACK. */ + +void +emit_unicode_mangled_name (obstack, name, len) + struct obstack *obstack; + char *name; +{ + unsigned char *ptr; + unsigned char *limit = (unsigned char *)name + len; + for (ptr = (unsigned char *) name; ptr < limit; ) + { + int ch = UTF8_GET(ptr, limit); + int emit_escape; + if (ch < 0) + { + error ("internal error - bad Utf8 string"); + break; + } + if (ch >= '0' && ch <= '9') + emit_escape = (ptr == (unsigned char*) name); + else + emit_escape = (ch < 'a' || ch > 'z') && (ch < 'A' || ch > 'Z'); + if (emit_escape) + { + char buf[6]; + sprintf (buf, "_%04x", ch); + obstack_grow (obstack, buf, 5); + } + else + { + obstack_1grow (obstack, ch); + } + } +} + +/* Assuming (NAME, LEN) is a Utf8-encoding string, emit the string + appropriately mangled (with Unicode escapes if needed) to OBSTACK. */ + +void +append_gpp_mangled_name (obstack, name, len) + struct obstack *obstack; + char *name; + int len; +{ + int encoded_len = unicode_mangling_length (name, len); + int needs_escapes = encoded_len > 0; + char buf[6]; + if (needs_escapes) + { + sprintf (buf, "U%d", encoded_len); + obstack_grow (obstack, buf, strlen(buf)); + emit_unicode_mangled_name (obstack, name, len); + } + else + { + sprintf (buf, "%d", len); + obstack_grow (obstack, buf, strlen(buf)); + obstack_grow (obstack, name, len); + } +} + +/* Append the mangled name of a class named CLASSNAME onto OBSTACK. */ + +void +append_gpp_mangled_classtype (obstack, class_name) + struct obstack *obstack; + char *class_name; +{ + char *ptr; + int qualifications = 0; + + for (ptr = class_name; *ptr != '\0'; ptr++) + { + if (*ptr == '.') + qualifications++; + } + if (qualifications) + { + char buf[8]; + if (qualifications >= 9) + sprintf (buf, "Q_%d_", qualifications + 1); + else + sprintf (buf, "Q%d", qualifications + 1); + obstack_grow (obstack, buf, strlen (buf)); + } + for (ptr = class_name; ; ptr++) + { + if (ptr[0] == '.' || ptr[0] == '\0') + { + append_gpp_mangled_name (obstack, class_name, ptr - class_name); + if (ptr[0] == '\0') + break; + class_name = ptr + 1; + } + } +} diff --git a/gcc/java/parse-scan.y b/gcc/java/parse-scan.y new file mode 100644 index 00000000000..11c9978c67e --- /dev/null +++ b/gcc/java/parse-scan.y @@ -0,0 +1,1162 @@ +/* Parser grammar for quick source code scan of Java(TM) language programs. + Copyright (C) 1998 Free Software Foundation, Inc. + Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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, +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 +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. Action can be further completed +to achieve a desired behavior. This file isn't part of the Java +language gcc front end. + +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" + +Some rules have been modified to support JDK1.1 inner classes +definitions and other extensions. */ + +%{ +#define JC1_LITE + +#include +#include +#include + +/* Definitions for PROTO and VPROTO macros */ +#include "gansidecl.h" +#include "obstack.h" + +extern char *input_filename; +extern FILE *finput, *out; + +/* Obstack for the lexer. */ +struct obstack temporary_obstack; + +/* The current parser context. */ +static struct parser_ctxt *ctxp; + +/* Error and warning counts, current line number, 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; +static char *package_name; + +/* Keep track of whether things have be listed before. */ +static int previous_output; + +/* Record modifier uses */ +static int modifier_value; + +/* Record a method declaration */ +struct method_declarator { + char *method_name; + char *args; +}; +#define NEW_METHOD_DECLARATOR(D,N,A) \ +{ \ + (D) = \ + (struct method_declarator *)xmalloc (sizeof (struct method_declarator)); \ + (D)->method_name = (N); \ + (D)->args = (A); \ +} + +/* Two actions for this grammar */ +static void report_class_declaration PROTO ((char *)); +static void report_main_declaration PROTO ((struct method_declarator *)); + +/* Other extern functions */ +char *xmalloc PROTO ((unsigned)); +char *xstrdup PROTO ((char *)); + +#include "lex.h" +#include "parse.h" +%} + +%union { + char *node; + struct method_declarator *declarator; + int value; /* For modifiers */ +} + +%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 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 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 ID_TK identifier name simple_name qualified_name type + primitive_type reference_type array_type formal_parameter_list + formal_parameter class_or_interface_type class_type interface_type +%type method_declarator +%type MODIFIER_TK + +%% +/* 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 + { + /* use preset global here. FIXME */ + $$ = xstrdup ("int"); + } +| FP_TK + { + /* use preset global here. FIXME */ + $$ = xstrdup ("double"); + } +| BOOLEAN_TK + { + /* use preset global here. FIXME */ + $$ = xstrdup ("boolean"); + } +; + +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 OSB_TK CSB_TK +| name OSB_TK CSB_TK + { + char *n = xmalloc (strlen ($1)+2); + n [0] = '['; + strcpy (n+1, $1); + $$ = n; + } +| array_type OSB_TK CSB_TK + { + char *n = xmalloc (strlen ($1)+2); + n [0] = '['; + strcpy (n+1, $1); + $$ = n; + } +; + +/* 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 + { + char *n = xmalloc (strlen ($1)+strlen ($3)+2); + sprintf (n, "%s.s", $1, $3); + $$ = n; + } +; + +identifier: + ID_TK +; + +/* 19.6: Production from 7: Packages */ +compilation_unit: +| 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 +| import_declarations import_declaration +; + +type_declarations: + type_declaration +| type_declarations type_declaration +; + +package_declaration: + PACKAGE_TK name SC_TK + { package_name = $2; } +; + +import_declaration: + single_type_import_declaration +| type_import_on_demand_declaration +; + +single_type_import_declaration: + IMPORT_TK name SC_TK +; + +type_import_on_demand_declaration: + IMPORT_TK name DOT_TK MULT_TK SC_TK +; + +type_declaration: + class_declaration +| interface_declaration +| SC_TK +; + +/* 19.7 Shortened from the original: + modifiers: modifier | modifiers modifier + modifier: any of public... */ +modifiers: + MODIFIER_TK + { + if ($1 == PUBLIC_TK) + modifier_value++; + if ($1 == STATIC_TK) + modifier_value++; + USE_ABSORBER; + } +| modifiers MODIFIER_TK + { + if ($2 == PUBLIC_TK) + modifier_value++; + if ($2 == STATIC_TK) + modifier_value++; + USE_ABSORBER; + } +; + +/* 19.8.1 Production from $8.1: Class Declaration */ +class_declaration: + modifiers CLASS_TK identifier super interfaces + { + report_class_declaration($3); + modifier_value = 0; + } + class_body +| CLASS_TK identifier super interfaces + { report_class_declaration($2); } + class_body +; + +super: +| EXTENDS_TK class_type +; + +interfaces: +| IMPLEMENTS_TK interface_type_list +; + +interface_type_list: + interface_type + { USE_ABSORBER; } +| interface_type_list C_TK interface_type + { USE_ABSORBER; } +; + +class_body: + OCB_TK CCB_TK +| OCB_TK class_body_declarations CCB_TK +; + +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 */ +; + +class_member_declaration: + field_declaration +| method_declaration +| class_declaration /* Added, JDK1.1 inner classes */ +| interface_declaration /* Added, JDK1.1 inner classes */ +; + +/* 19.8.2 Productions from 8.3: Field Declarations */ +field_declaration: + type variable_declarators SC_TK + { USE_ABSORBER; } +| modifiers type variable_declarators SC_TK + { modifier_value = 0; } +; + +variable_declarators: + /* Should we use build_decl_list () instead ? FIXME */ + variable_declarator /* Default rule */ +| variable_declarators C_TK variable_declarator +; + +variable_declarator: + variable_declarator_id +| variable_declarator_id ASSIGN_TK variable_initializer +; + +variable_declarator_id: + identifier + { USE_ABSORBER; } +| variable_declarator_id OSB_TK CSB_TK +; + +variable_initializer: + expression +| array_initializer +; + +/* 19.8.3 Productions from 8.4: Method Declarations */ +method_declaration: + method_header method_body +; + +method_header: + type method_declarator throws + { USE_ABSORBER; } +| VOID_TK method_declarator throws +| modifiers type method_declarator throws + { modifier_value = 0; } +| modifiers VOID_TK method_declarator throws + { + report_main_declaration ($3); + modifier_value = 0; + } +; + +method_declarator: + identifier OP_TK CP_TK + { + struct method_declarator *d; + NEW_METHOD_DECLARATOR (d, $1, NULL); + $$ = d; + } +| identifier OP_TK formal_parameter_list CP_TK + { + struct method_declarator *d; + NEW_METHOD_DECLARATOR (d, $1, $3); + $$ = d; + } +| method_declarator OSB_TK CSB_TK +; + +formal_parameter_list: + formal_parameter +| formal_parameter_list C_TK formal_parameter + { + char *n = xmalloc (strlen ($1)+strlen($3)+2); + sprintf (n, "%s,%s", $1, $3); + $$ = n; + } +; + +formal_parameter: + type variable_declarator_id + { + USE_ABSORBER; + $$ = $1; + } +| modifiers type variable_declarator_id /* Added, JDK1.1 final locals */ + { $$ = $2; } +; + +throws: +| THROWS_TK class_type_list +; + +class_type_list: + class_type + { USE_ABSORBER; } +| class_type_list C_TK class_type + { USE_ABSORBER; } +; + +method_body: + block +| block SC_TK +| SC_TK +; + +/* 19.8.4 Productions from 8.5: Static Initializers */ +static_initializer: + static block +| static block SC_TK /* Shouldn't be here. FIXME */ +; + +static: /* Test lval.sub_token here */ + MODIFIER_TK + { USE_ABSORBER; } +; + +/* 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 + method without having specified the return type. FIXME */ +constructor_declaration: + constructor_declarator throws constructor_body +| modifiers constructor_declarator throws constructor_body + { modifier_value = 0; } +/* extra SC_TK, FIXME */ +| constructor_declarator throws constructor_body SC_TK +/* 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 + probably be matched by and empty statement. But it doesn't work. FIXME */ +; + +constructor_declarator: + simple_name OP_TK CP_TK + { USE_ABSORBER; } +| simple_name OP_TK formal_parameter_list CP_TK + { USE_ABSORBER; } +; + +constructor_body: + OCB_TK CCB_TK +| OCB_TK explicit_constructor_invocation CCB_TK +| OCB_TK block_statements CCB_TK +| OCB_TK explicit_constructor_invocation block_statements CCB_TK +; + +/* Error recovery for that rule moved down expression_statement: rule. */ +explicit_constructor_invocation: + this_or_super OP_TK CP_TK SC_TK +| this_or_super OP_TK argument_list CP_TK SC_TK + /* 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 + { USE_ABSORBER; } +| name DOT_TK SUPER_TK OP_TK CP_TK SC_TK + { USE_ABSORBER; } +; + +this_or_super: /* Added, simplifies error diagnostics */ + THIS_TK +| SUPER_TK +; + +/* 19.9 Productions from 9: Interfaces */ +/* 19.9.1 Productions from 9.1: Interfaces Declarations */ +interface_declaration: + INTERFACE_TK identifier interface_body +| modifiers INTERFACE_TK identifier interface_body + { modifier_value = 0; } +| INTERFACE_TK identifier extends_interfaces interface_body +| modifiers INTERFACE_TK identifier extends_interfaces interface_body + { modifier_value = 0; } +; + +extends_interfaces: + EXTENDS_TK interface_type +| extends_interfaces C_TK interface_type +; + +interface_body: + OCB_TK CCB_TK +| OCB_TK interface_member_declarations CCB_TK +; + +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 */ +| interface_declaration /* Added, JDK1.1 inner classes */ +; + +constant_declaration: + field_declaration +; + +abstract_method_declaration: + method_header SC_TK +; + +/* 19.10 Productions from 10: Arrays */ +array_initializer: + OCB_TK CCB_TK +| OCB_TK variable_initializers CCB_TK +| OCB_TK C_TK CCB_TK +| OCB_TK variable_initializers C_TK CCB_TK +; + +variable_initializers: + variable_initializer +| variable_initializers C_TK variable_initializer +; + +/* 19.11 Production from 14: Blocks and Statements */ +block: + OCB_TK CCB_TK +| OCB_TK block_statements CCB_TK +; + +block_statements: + block_statement +| block_statements block_statement +; + +block_statement: + local_variable_declaration_statement +| statement +| class_declaration /* Added, JDK1.1 inner classes */ +; + +local_variable_declaration_statement: + local_variable_declaration SC_TK /* Can't catch missing ';' here */ +; + +local_variable_declaration: + type variable_declarators + { USE_ABSORBER; } +| modifiers type variable_declarators /* Added, JDK1.1 final locals */ + { modifier_value = 0; } +; + +statement: + statement_without_trailing_substatement +| labeled_statement +| if_then_statement +| if_then_else_statement +| while_statement +| for_statement +; + +statement_nsi: + statement_without_trailing_substatement +| labeled_statement_nsi +| if_then_else_statement_nsi +| while_statement_nsi +| for_statement_nsi +; + +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 +; + +empty_statement: + SC_TK +; + +label_decl: + identifier REL_CL_TK + { USE_ABSORBER; } +; + +labeled_statement: + label_decl statement +; + +labeled_statement_nsi: + label_decl statement_nsi +; + +/* 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 +; + +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 +; + +if_then_else_statement: + IF_TK OP_TK expression CP_TK statement_nsi ELSE_TK statement +; + +if_then_else_statement_nsi: + IF_TK OP_TK expression CP_TK statement_nsi ELSE_TK statement_nsi +; + +switch_statement: + SWITCH_TK OP_TK expression CP_TK switch_block +; + +switch_block: + OCB_TK CCB_TK +| OCB_TK switch_labels CCB_TK +| OCB_TK switch_block_statement_groups CCB_TK +| OCB_TK switch_block_statement_groups switch_labels CCB_TK +; + +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 +| DEFAULT_TK REL_CL_TK +; + +while_expression: + WHILE_TK OP_TK expression CP_TK +; + +while_statement: + while_expression statement +; + +while_statement_nsi: + while_expression statement_nsi +; + +do_statement_begin: + DO_TK +; + +do_statement: + do_statement_begin statement WHILE_TK OP_TK expression CP_TK SC_TK +; + +for_statement: + for_begin SC_TK expression SC_TK for_update CP_TK statement +| for_begin SC_TK SC_TK for_update CP_TK statement +; + +for_statement_nsi: + for_begin SC_TK expression SC_TK for_update CP_TK statement_nsi +| for_begin SC_TK SC_TK for_update CP_TK statement_nsi +; + +for_header: + FOR_TK OP_TK +; + +for_begin: + for_header for_init +; +for_init: /* Can be empty */ +| statement_expression_list +| local_variable_declaration +; + +for_update: /* Can be empty */ +| statement_expression_list +; + +statement_expression_list: + statement_expression +| statement_expression_list C_TK statement_expression +; + +break_statement: + BREAK_TK SC_TK +| BREAK_TK identifier SC_TK +; + +continue_statement: + CONTINUE_TK SC_TK +| CONTINUE_TK identifier SC_TK +; + +return_statement: + RETURN_TK SC_TK +| RETURN_TK expression SC_TK +; + +throw_statement: + THROW_TK expression SC_TK +; + +synchronized_statement: + synchronized OP_TK expression CP_TK block +| synchronized OP_TK expression CP_TK error +; + +synchronized: /* Test lval.sub_token here */ + MODIFIER_TK + { USE_ABSORBER; } +; + +try_statement: + TRY_TK block catches +| TRY_TK block finally +| TRY_TK block catches finally +; + +catches: + catch_clause +| catches catch_clause +; + +catch_clause: + CATCH_TK OP_TK formal_parameter CP_TK block +; + +finally: + FINALLY_TK block +; + +/* 19.12 Production from 15: Expressions */ +primary: + primary_no_new_array +| array_creation_expression +; + +primary_no_new_array: + literal +| THIS_TK +| OP_TK expression CP_TK +| class_instance_creation_expression +| field_access +| method_invocation +| array_access + /* type DOT_TK CLASS_TK doens't work. So we split the rule + 'type' into its components. Missing is something for array, + which will complete the reference_type part. FIXME */ +| name DOT_TK CLASS_TK /* Added, JDK1.1 class literals */ + { USE_ABSORBER; } +| primitive_type DOT_TK CLASS_TK /* Added, JDK1.1 class literals */ + { USE_ABSORBER; } +| VOID_TK DOT_TK CLASS_TK /* Added, JDK1.1 class literals */ + /* Added, JDK1.1 inner classes. Documentation is wrong + refering to a 'ClassName' (class_name) rule that doesn't + exist. Used name instead. */ +| name DOT_TK THIS_TK + { USE_ABSORBER; } +; + +class_instance_creation_expression: + NEW_TK class_type OP_TK argument_list CP_TK +| NEW_TK class_type OP_TK CP_TK + /* Added, JDK1.1 inner classes but modified to use + 'class_type' instead of 'TypeName' (type_name) mentionned + in the documentation but doesn't exist. */ +| NEW_TK class_type OP_TK argument_list CP_TK class_body +| NEW_TK class_type OP_TK CP_TK class_body + /* 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 +| something_dot_new identifier OP_TK CP_TK class_body +| something_dot_new identifier OP_TK argument_list CP_TK +| something_dot_new identifier OP_TK argument_list CP_TK class_body +; + +something_dot_new: /* Added, not part of the specs. */ + name DOT_TK NEW_TK + { USE_ABSORBER; } +| primary DOT_TK NEW_TK +; + +argument_list: + expression +| argument_list C_TK expression +| argument_list C_TK error +; + +array_creation_expression: + NEW_TK primitive_type dim_exprs +| NEW_TK class_or_interface_type dim_exprs +| NEW_TK primitive_type dim_exprs dims +| NEW_TK class_or_interface_type dim_exprs dims + /* Added, JDK1.1 anonymous array. Initial documentation rule + modified */ +| NEW_TK class_or_interface_type dims array_initializer +| NEW_TK primitive_type dims array_initializer +; + +dim_exprs: + dim_expr +| dim_exprs dim_expr +; + +dim_expr: + OSB_TK expression CSB_TK +; + +dims: + OSB_TK CSB_TK +| dims OSB_TK CSB_TK +; + +field_access: + primary DOT_TK identifier +| SUPER_TK DOT_TK identifier +; + +method_invocation: + name OP_TK CP_TK + { USE_ABSORBER; } +| name OP_TK argument_list CP_TK + { USE_ABSORBER; } +| primary DOT_TK identifier OP_TK CP_TK +| primary DOT_TK identifier OP_TK argument_list CP_TK +| SUPER_TK DOT_TK identifier OP_TK CP_TK +| SUPER_TK DOT_TK identifier OP_TK argument_list CP_TK +; + +array_access: + name OSB_TK expression CSB_TK + { USE_ABSORBER; } +| primary_no_new_array OSB_TK expression CSB_TK +; + +postfix_expression: + primary +| name + { USE_ABSORBER; } +| post_increment_expression +| post_decrement_expression +; + +post_increment_expression: + postfix_expression INCR_TK +; + +post_decrement_expression: + postfix_expression DECR_TK +; + +unary_expression: + pre_increment_expression +| pre_decrement_expression +| PLUS_TK unary_expression +| MINUS_TK unary_expression +| unary_expression_not_plus_minus +; + +pre_increment_expression: + INCR_TK unary_expression +; + +pre_decrement_expression: + DECR_TK unary_expression +; + +unary_expression_not_plus_minus: + postfix_expression +| NOT_TK unary_expression +| NEG_TK unary_expression +| cast_expression +; + +cast_expression: /* Error handling here is potentially weak */ + OP_TK primitive_type dims CP_TK unary_expression +| OP_TK primitive_type CP_TK unary_expression +| OP_TK expression CP_TK unary_expression_not_plus_minus +| OP_TK name dims CP_TK unary_expression_not_plus_minus +; + +multiplicative_expression: + unary_expression +| multiplicative_expression MULT_TK unary_expression +| multiplicative_expression DIV_TK unary_expression +| multiplicative_expression REM_TK unary_expression +; + +additive_expression: + multiplicative_expression +| additive_expression PLUS_TK multiplicative_expression +| additive_expression MINUS_TK multiplicative_expression +; + +shift_expression: + additive_expression +| shift_expression LS_TK additive_expression +| shift_expression SRS_TK additive_expression +| shift_expression ZRS_TK additive_expression +; + +relational_expression: + shift_expression +| relational_expression LT_TK shift_expression +| relational_expression GT_TK shift_expression +| relational_expression LTE_TK shift_expression +| relational_expression GTE_TK shift_expression +| relational_expression INSTANCEOF_TK reference_type +; + +equality_expression: + relational_expression +| equality_expression EQ_TK relational_expression +| equality_expression NEQ_TK relational_expression +; + +and_expression: + equality_expression +| and_expression AND_TK equality_expression +; + +exclusive_or_expression: + and_expression +| exclusive_or_expression XOR_TK and_expression +; + +inclusive_or_expression: + exclusive_or_expression +| inclusive_or_expression OR_TK exclusive_or_expression +; + +conditional_and_expression: + inclusive_or_expression +| conditional_and_expression BOOL_AND_TK inclusive_or_expression +; + +conditional_or_expression: + conditional_and_expression +| conditional_or_expression BOOL_OR_TK conditional_and_expression +; + +conditional_expression: /* Error handling here is weak */ + conditional_or_expression +| conditional_or_expression REL_QM_TK expression REL_CL_TK conditional_expression +; + +assignment_expression: + conditional_expression +| assignment +; + +assignment: + left_hand_side assignment_operator assignment_expression +; + +left_hand_side: + name + { USE_ABSORBER; } +| field_access +| array_access +; + +assignment_operator: + ASSIGN_ANY_TK +| ASSIGN_TK +; + +expression: + assignment_expression +; + +constant_expression: + expression +; + +%% + +#include "lex.c" + +/* Create a new parser context */ + +void +java_push_parser_context () +{ + struct parser_ctxt *new = + (struct parser_ctxt *)xmalloc(sizeof (struct parser_ctxt)); + + bzero (new, sizeof (struct parser_ctxt)); + new->next = ctxp; + ctxp = new; +} + +/* Actions defined here */ + +static void +report_class_declaration (name) + char * name; +{ + extern int flag_dump_class, flag_list_filename; + + if (flag_dump_class) + { + if (!previous_output) + { + if (flag_list_filename) + fprintf (out, "%s: ", input_filename); + previous_output = 1; + } + + if (package_name) + fprintf (out, "%s.%s ", package_name, name); + else + fprintf (out, "%s ", name); + } + + current_class = name; +} + +static void +report_main_declaration (declarator) + struct method_declarator *declarator; +{ + extern int flag_find_main; + + if (flag_find_main + && modifier_value == 2 + && !strcmp (declarator->method_name, "main") + && declarator->args + && declarator->args [0] == '[' + && !strcmp( declarator->args+1, "String") + && current_class) + { + if (!previous_output) + { + if (package_name) + fprintf (out, "%s.%s ", package_name, current_class); + else + fprintf (out, current_class); + previous_output = 1; + } + } +} + +/* Reset global status used by the report functions. */ + +void reset_report () +{ + previous_output = 0; + current_class = package_name = NULL; +} + +void +yyerror (msg) + char *msg; +{ +} diff --git a/gcc/java/parse.c b/gcc/java/parse.c new file mode 100644 index 00000000000..224ae38c7f6 --- /dev/null +++ b/gcc/java/parse.c @@ -0,0 +1,10648 @@ + +/* A Bison parser, made from /nfs/hoser/beer/java/egcs/gcc/java/parse.y + by GNU Bison version 1.25 + */ + +#define YYBISON 1 /* Identify Bison output. */ + +#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 yynerrs java_nerrs +#define PLUS_TK 258 +#define MINUS_TK 259 +#define MULT_TK 260 +#define DIV_TK 261 +#define REM_TK 262 +#define LS_TK 263 +#define SRS_TK 264 +#define ZRS_TK 265 +#define AND_TK 266 +#define XOR_TK 267 +#define OR_TK 268 +#define BOOL_AND_TK 269 +#define BOOL_OR_TK 270 +#define EQ_TK 271 +#define NEQ_TK 272 +#define GT_TK 273 +#define GTE_TK 274 +#define LT_TK 275 +#define LTE_TK 276 +#define PLUS_ASSIGN_TK 277 +#define MINUS_ASSIGN_TK 278 +#define MULT_ASSIGN_TK 279 +#define DIV_ASSIGN_TK 280 +#define REM_ASSIGN_TK 281 +#define LS_ASSIGN_TK 282 +#define SRS_ASSIGN_TK 283 +#define ZRS_ASSIGN_TK 284 +#define AND_ASSIGN_TK 285 +#define XOR_ASSIGN_TK 286 +#define OR_ASSIGN_TK 287 +#define PUBLIC_TK 288 +#define PRIVATE_TK 289 +#define PROTECTED_TK 290 +#define STATIC_TK 291 +#define FINAL_TK 292 +#define SYNCHRONIZED_TK 293 +#define VOLATILE_TK 294 +#define TRANSIENT_TK 295 +#define NATIVE_TK 296 +#define PAD_TK 297 +#define ABSTRACT_TK 298 +#define MODIFIER_TK 299 +#define DECR_TK 300 +#define INCR_TK 301 +#define DEFAULT_TK 302 +#define IF_TK 303 +#define THROW_TK 304 +#define BOOLEAN_TK 305 +#define DO_TK 306 +#define IMPLEMENTS_TK 307 +#define THROWS_TK 308 +#define BREAK_TK 309 +#define IMPORT_TK 310 +#define ELSE_TK 311 +#define INSTANCEOF_TK 312 +#define RETURN_TK 313 +#define VOID_TK 314 +#define CATCH_TK 315 +#define INTERFACE_TK 316 +#define CASE_TK 317 +#define EXTENDS_TK 318 +#define FINALLY_TK 319 +#define SUPER_TK 320 +#define WHILE_TK 321 +#define CLASS_TK 322 +#define SWITCH_TK 323 +#define CONST_TK 324 +#define TRY_TK 325 +#define FOR_TK 326 +#define NEW_TK 327 +#define CONTINUE_TK 328 +#define GOTO_TK 329 +#define PACKAGE_TK 330 +#define THIS_TK 331 +#define BYTE_TK 332 +#define SHORT_TK 333 +#define INT_TK 334 +#define LONG_TK 335 +#define CHAR_TK 336 +#define INTEGRAL_TK 337 +#define FLOAT_TK 338 +#define DOUBLE_TK 339 +#define FP_TK 340 +#define ID_TK 341 +#define REL_QM_TK 342 +#define REL_CL_TK 343 +#define NOT_TK 344 +#define NEG_TK 345 +#define ASSIGN_ANY_TK 346 +#define ASSIGN_TK 347 +#define OP_TK 348 +#define CP_TK 349 +#define OCB_TK 350 +#define CCB_TK 351 +#define OSB_TK 352 +#define CSB_TK 353 +#define SC_TK 354 +#define C_TK 355 +#define DOT_TK 356 +#define STRING_LIT_TK 357 +#define CHAR_LIT_TK 358 +#define INT_LIT_TK 359 +#define FP_LIT_TK 360 +#define TRUE_TK 361 +#define FALSE_TK 362 +#define BOOL_LIT_TK 363 +#define NULL_TK 364 + +#line 49 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" + +#include +#include +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif + +#include "config.h" +#include "tree.h" +#include "rtl.h" +#include "obstack.h" +#include "flags.h" +#include "java-tree.h" +#include "jcf.h" +#include "lex.h" +#include "parse.h" +#include "zipfile.h" + +/* Number of error found so far. */ +int java_error_count; +/* Number of warning found so far. */ +int java_warning_count; + +/* The current parser context */ +static struct parser_ctxt *ctxp; + +/* 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 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)% \ + (sizeof (binop_lookup) / sizeof (binop_lookup[0]))] + +/* Fake WFL used to report error message. It is initialized once if + needed and reused with it's location information is overriden. */ +static tree wfl_operator = NULL_TREE; + +/* The "$L" identifier we use to create labels. */ +static tree label_id; + +#line 104 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +typedef union { + tree node; + int sub_token; + struct { + int token; + int location; + } operator; + int value; +} YYSTYPE; +#ifndef YYDEBUG +#define YYDEBUG 1 +#endif + +#include + +#ifndef __cplusplus +#ifndef __STDC__ +#define const +#endif +#endif + + + +#define YYFINAL 772 +#define YYFLAG -32768 +#define YYNTBASE 110 + +#define YYTRANSLATE(x) ((unsigned)(x) <= 364 ? yytranslate[x] : 259) + +static const char yytranslate[] = { 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, + 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, + 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, + 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, + 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, + 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, + 106, 107, 108, 109 +}; + +#if YYDEBUG != 0 +static const short yyprhs[] = { 0, + 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, + 20, 22, 24, 26, 28, 30, 32, 34, 38, 42, + 46, 50, 54, 56, 58, 60, 64, 66, 67, 69, + 71, 73, 76, 79, 82, 86, 88, 91, 93, 96, + 100, 103, 107, 109, 111, 115, 118, 122, 128, 133, + 139, 141, 143, 145, 147, 149, 152, 153, 161, 162, + 169, 173, 176, 180, 185, 186, 189, 193, 196, 197, + 200, 203, 205, 209, 213, 216, 220, 222, 225, 227, + 229, 231, 233, 235, 237, 239, 241, 245, 250, 252, + 256, 260, 262, 266, 270, 275, 277, 281, 284, 288, + 292, 294, 296, 297, 301, 304, 308, 312, 317, 322, + 325, 329, 332, 336, 339, 343, 348, 352, 356, 360, + 362, 366, 370, 373, 377, 380, 384, 385, 388, 391, + 393, 397, 401, 403, 406, 408, 411, 415, 417, 421, + 426, 431, 437, 441, 446, 449, 453, 457, 462, 467, + 473, 481, 488, 490, 492, 493, 498, 499, 505, 506, + 512, 513, 520, 524, 529, 532, 536, 539, 543, 546, + 550, 552, 555, 557, 559, 561, 563, 565, 568, 571, + 574, 578, 582, 587, 589, 593, 597, 600, 601, 606, + 608, 611, 613, 615, 617, 620, 623, 627, 629, 631, + 633, 635, 637, 639, 641, 643, 645, 647, 649, 651, + 653, 655, 657, 659, 661, 663, 665, 667, 669, 671, + 673, 676, 679, 682, 685, 688, 691, 694, 697, 701, + 706, 711, 717, 722, 728, 735, 743, 750, 752, 754, + 756, 758, 760, 762, 764, 770, 773, 777, 782, 790, + 798, 804, 807, 811, 817, 820, 824, 828, 833, 835, + 838, 841, 843, 846, 850, 853, 856, 860, 863, 868, + 871, 874, 878, 883, 886, 888, 896, 904, 911, 915, + 921, 926, 934, 941, 944, 947, 951, 954, 955, 957, + 959, 962, 963, 965, 967, 971, 975, 978, 982, 985, + 989, 992, 996, 999, 1003, 1006, 1010, 1013, 1017, 1021, + 1024, 1028, 1034, 1040, 1043, 1048, 1052, 1054, 1058, 1062, + 1067, 1070, 1072, 1075, 1081, 1084, 1089, 1093, 1096, 1099, + 1101, 1103, 1105, 1107, 1111, 1113, 1115, 1117, 1119, 1123, + 1127, 1131, 1135, 1139, 1143, 1147, 1151, 1157, 1162, 1169, + 1175, 1180, 1186, 1192, 1199, 1203, 1207, 1212, 1218, 1221, + 1225, 1229, 1233, 1235, 1239, 1243, 1247, 1251, 1256, 1261, + 1266, 1271, 1275, 1279, 1281, 1284, 1288, 1292, 1295, 1298, + 1302, 1306, 1310, 1314, 1317, 1321, 1326, 1332, 1339, 1345, + 1352, 1357, 1362, 1367, 1372, 1376, 1381, 1385, 1390, 1392, + 1394, 1396, 1398, 1401, 1404, 1406, 1408, 1411, 1414, 1416, + 1419, 1422, 1425, 1428, 1431, 1434, 1436, 1439, 1442, 1444, + 1447, 1450, 1456, 1461, 1466, 1472, 1477, 1480, 1486, 1491, + 1497, 1499, 1503, 1507, 1511, 1515, 1519, 1523, 1525, 1529, + 1533, 1537, 1541, 1543, 1547, 1551, 1555, 1559, 1563, 1567, + 1569, 1573, 1577, 1581, 1585, 1589, 1593, 1597, 1601, 1605, + 1609, 1611, 1615, 1619, 1623, 1627, 1629, 1633, 1637, 1639, + 1643, 1647, 1649, 1653, 1657, 1659, 1663, 1667, 1669, 1673, + 1677, 1679, 1685, 1690, 1694, 1700, 1702, 1704, 1708, 1712, + 1714, 1716, 1718, 1720, 1722, 1724 +}; + +static const short yyrhs[] = { 123, + 0, 104, 0, 105, 0, 108, 0, 103, 0, 102, + 0, 109, 0, 113, 0, 114, 0, 82, 0, 85, + 0, 50, 0, 115, 0, 118, 0, 119, 0, 115, + 0, 115, 0, 113, 97, 98, 0, 119, 97, 98, + 0, 118, 97, 98, 0, 113, 97, 1, 0, 118, + 97, 1, 0, 120, 0, 121, 0, 122, 0, 119, + 101, 122, 0, 86, 0, 0, 126, 0, 124, 0, + 125, 0, 126, 124, 0, 126, 125, 0, 124, 125, + 0, 126, 124, 125, 0, 127, 0, 124, 127, 0, + 130, 0, 125, 130, 0, 75, 119, 99, 0, 75, + 1, 0, 75, 119, 1, 0, 128, 0, 129, 0, + 55, 119, 99, 0, 55, 1, 0, 55, 119, 1, + 0, 55, 119, 101, 5, 99, 0, 55, 119, 101, + 1, 0, 55, 119, 101, 5, 1, 0, 132, 0, + 163, 0, 99, 0, 1, 0, 44, 0, 131, 44, + 0, 0, 131, 67, 122, 135, 136, 133, 138, 0, + 0, 67, 122, 135, 136, 134, 138, 0, 131, 67, + 1, 0, 67, 1, 0, 67, 122, 1, 0, 131, + 67, 122, 1, 0, 0, 63, 116, 0, 63, 116, + 1, 0, 63, 1, 0, 0, 52, 137, 0, 52, + 1, 0, 117, 0, 137, 100, 117, 0, 137, 100, + 1, 0, 95, 96, 0, 95, 139, 96, 0, 140, + 0, 139, 140, 0, 141, 0, 156, 0, 158, 0, + 176, 0, 142, 0, 147, 0, 132, 0, 163, 0, + 112, 143, 99, 0, 131, 112, 143, 99, 0, 144, + 0, 143, 100, 144, 0, 143, 100, 1, 0, 145, + 0, 145, 92, 146, 0, 145, 92, 1, 0, 145, + 92, 146, 1, 0, 122, 0, 145, 97, 98, 0, + 122, 1, 0, 145, 97, 1, 0, 145, 98, 1, + 0, 257, 0, 174, 0, 0, 149, 148, 155, 0, + 149, 1, 0, 112, 150, 153, 0, 59, 150, 153, + 0, 131, 112, 150, 153, 0, 131, 59, 150, 153, + 0, 112, 1, 0, 131, 112, 1, 0, 59, 1, + 0, 131, 59, 1, 0, 131, 1, 0, 122, 93, + 94, 0, 122, 93, 151, 94, 0, 150, 97, 98, + 0, 122, 93, 1, 0, 150, 97, 1, 0, 152, + 0, 151, 100, 152, 0, 151, 100, 1, 0, 112, + 145, 0, 131, 112, 145, 0, 112, 1, 0, 131, + 112, 1, 0, 0, 53, 154, 0, 53, 1, 0, + 116, 0, 154, 100, 116, 0, 154, 100, 1, 0, + 176, 0, 176, 99, 0, 99, 0, 157, 176, 0, + 157, 176, 99, 0, 44, 0, 159, 153, 160, 0, + 131, 159, 153, 160, 0, 159, 153, 160, 99, 0, + 131, 159, 153, 160, 99, 0, 120, 93, 94, 0, + 120, 93, 151, 94, 0, 95, 96, 0, 95, 161, + 96, 0, 95, 178, 96, 0, 95, 161, 178, 96, + 0, 162, 93, 94, 99, 0, 162, 93, 226, 94, + 99, 0, 119, 101, 65, 93, 226, 94, 99, 0, + 119, 101, 65, 93, 94, 99, 0, 76, 0, 65, + 0, 0, 61, 122, 164, 169, 0, 0, 131, 61, + 122, 165, 169, 0, 0, 61, 122, 168, 166, 169, + 0, 0, 131, 61, 122, 168, 167, 169, 0, 61, + 122, 1, 0, 131, 61, 122, 1, 0, 63, 117, + 0, 168, 100, 117, 0, 63, 1, 0, 168, 100, + 1, 0, 95, 96, 0, 95, 170, 96, 0, 171, + 0, 170, 171, 0, 172, 0, 173, 0, 132, 0, + 163, 0, 142, 0, 149, 99, 0, 149, 1, 0, + 95, 96, 0, 95, 175, 96, 0, 95, 100, 96, + 0, 95, 175, 100, 96, 0, 146, 0, 175, 100, + 146, 0, 175, 100, 1, 0, 95, 96, 0, 0, + 95, 177, 178, 96, 0, 179, 0, 178, 179, 0, + 180, 0, 182, 0, 132, 0, 181, 99, 0, 112, + 143, 0, 131, 112, 143, 0, 184, 0, 187, 0, + 191, 0, 192, 0, 201, 0, 205, 0, 184, 0, + 188, 0, 193, 0, 202, 0, 206, 0, 176, 0, + 185, 0, 189, 0, 194, 0, 204, 0, 212, 0, + 213, 0, 214, 0, 216, 0, 215, 0, 218, 0, + 99, 0, 122, 88, 0, 186, 182, 0, 122, 1, + 0, 186, 183, 0, 190, 99, 0, 1, 99, 0, + 1, 95, 0, 1, 96, 0, 162, 93, 1, 0, + 162, 93, 94, 1, 0, 162, 93, 226, 1, 0, + 162, 93, 226, 94, 1, 0, 119, 101, 65, 1, + 0, 119, 101, 65, 93, 1, 0, 119, 101, 65, + 93, 226, 1, 0, 119, 101, 65, 93, 226, 94, + 1, 0, 119, 101, 65, 93, 94, 1, 0, 254, + 0, 238, 0, 239, 0, 235, 0, 236, 0, 232, + 0, 224, 0, 48, 93, 257, 94, 182, 0, 48, + 1, 0, 48, 93, 1, 0, 48, 93, 257, 1, + 0, 48, 93, 257, 94, 183, 56, 182, 0, 48, + 93, 257, 94, 183, 56, 183, 0, 68, 93, 257, + 94, 195, 0, 68, 1, 0, 68, 93, 1, 0, + 68, 93, 257, 94, 1, 0, 95, 96, 0, 95, + 198, 96, 0, 95, 196, 96, 0, 95, 196, 198, + 96, 0, 197, 0, 196, 197, 0, 198, 178, 0, + 199, 0, 198, 199, 0, 62, 258, 88, 0, 47, + 88, 0, 62, 1, 0, 62, 258, 1, 0, 47, + 1, 0, 66, 93, 257, 94, 0, 200, 182, 0, + 66, 1, 0, 66, 93, 1, 0, 66, 93, 257, + 1, 0, 200, 183, 0, 51, 0, 203, 182, 66, + 93, 257, 94, 99, 0, 208, 99, 257, 99, 210, + 94, 182, 0, 208, 99, 99, 210, 94, 182, 0, + 208, 99, 1, 0, 208, 99, 257, 99, 1, 0, + 208, 99, 99, 1, 0, 208, 99, 257, 99, 210, + 94, 183, 0, 208, 99, 99, 210, 94, 183, 0, + 71, 93, 0, 71, 1, 0, 71, 93, 1, 0, + 207, 209, 0, 0, 211, 0, 181, 0, 211, 1, + 0, 0, 211, 0, 190, 0, 211, 100, 190, 0, + 211, 100, 1, 0, 54, 99, 0, 54, 122, 99, + 0, 54, 1, 0, 54, 122, 1, 0, 73, 99, + 0, 73, 122, 99, 0, 73, 1, 0, 73, 122, + 1, 0, 58, 99, 0, 58, 257, 99, 0, 58, + 1, 0, 58, 257, 1, 0, 49, 257, 99, 0, + 49, 1, 0, 49, 257, 1, 0, 217, 93, 257, + 94, 176, 0, 217, 93, 257, 94, 1, 0, 217, + 1, 0, 217, 93, 1, 94, 0, 217, 93, 1, + 0, 44, 0, 70, 176, 219, 0, 70, 176, 221, + 0, 70, 176, 219, 221, 0, 70, 1, 0, 220, + 0, 219, 220, 0, 60, 93, 152, 94, 176, 0, + 60, 1, 0, 60, 93, 1, 94, 0, 60, 93, + 1, 0, 64, 176, 0, 64, 1, 0, 223, 0, + 227, 0, 111, 0, 76, 0, 93, 257, 94, 0, + 224, 0, 231, 0, 232, 0, 233, 0, 119, 101, + 67, 0, 113, 101, 67, 0, 59, 101, 67, 0, + 119, 101, 76, 0, 93, 257, 1, 0, 119, 101, + 1, 0, 113, 101, 1, 0, 59, 101, 1, 0, + 72, 116, 93, 226, 94, 0, 72, 116, 93, 94, + 0, 72, 116, 93, 226, 94, 138, 0, 72, 116, + 93, 94, 138, 0, 225, 122, 93, 94, 0, 225, + 122, 93, 94, 138, 0, 225, 122, 93, 226, 94, + 0, 225, 122, 93, 226, 94, 138, 0, 72, 1, + 99, 0, 72, 116, 1, 0, 72, 116, 93, 1, + 0, 72, 116, 93, 226, 1, 0, 225, 1, 0, + 225, 122, 1, 0, 119, 101, 72, 0, 222, 101, + 72, 0, 257, 0, 226, 100, 257, 0, 226, 100, + 1, 0, 72, 113, 228, 0, 72, 115, 228, 0, + 72, 113, 228, 230, 0, 72, 115, 228, 230, 0, + 72, 115, 230, 174, 0, 72, 113, 230, 174, 0, + 72, 1, 98, 0, 72, 1, 97, 0, 229, 0, + 228, 229, 0, 97, 257, 98, 0, 97, 257, 1, + 0, 97, 1, 0, 97, 98, 0, 230, 97, 98, + 0, 230, 97, 1, 0, 222, 101, 122, 0, 65, + 101, 122, 0, 65, 1, 0, 119, 93, 94, 0, + 119, 93, 226, 94, 0, 222, 101, 122, 93, 94, + 0, 222, 101, 122, 93, 226, 94, 0, 65, 101, + 122, 93, 94, 0, 65, 101, 122, 93, 226, 94, + 0, 65, 101, 1, 94, 0, 65, 101, 1, 101, + 0, 119, 97, 257, 98, 0, 223, 97, 257, 98, + 0, 119, 97, 1, 0, 119, 97, 257, 1, 0, + 223, 97, 1, 0, 223, 97, 257, 1, 0, 222, + 0, 119, 0, 235, 0, 236, 0, 234, 46, 0, + 234, 45, 0, 238, 0, 239, 0, 3, 237, 0, + 4, 237, 0, 240, 0, 3, 1, 0, 4, 1, + 0, 46, 237, 0, 46, 1, 0, 45, 237, 0, + 45, 1, 0, 234, 0, 89, 237, 0, 90, 237, + 0, 241, 0, 89, 1, 0, 90, 1, 0, 93, + 113, 230, 94, 237, 0, 93, 113, 94, 237, 0, + 93, 257, 94, 240, 0, 93, 119, 230, 94, 240, + 0, 93, 113, 97, 1, 0, 93, 1, 0, 93, + 113, 230, 94, 1, 0, 93, 113, 94, 1, 0, + 93, 119, 230, 94, 1, 0, 237, 0, 242, 5, + 237, 0, 242, 6, 237, 0, 242, 7, 237, 0, + 242, 5, 1, 0, 242, 6, 1, 0, 242, 7, + 1, 0, 242, 0, 243, 3, 242, 0, 243, 4, + 242, 0, 243, 3, 1, 0, 243, 4, 1, 0, + 243, 0, 244, 8, 243, 0, 244, 9, 243, 0, + 244, 10, 243, 0, 244, 8, 1, 0, 244, 9, + 1, 0, 244, 10, 1, 0, 244, 0, 245, 20, + 244, 0, 245, 18, 244, 0, 245, 21, 244, 0, + 245, 19, 244, 0, 245, 57, 114, 0, 245, 20, + 1, 0, 245, 18, 1, 0, 245, 21, 1, 0, + 245, 19, 1, 0, 245, 57, 1, 0, 245, 0, + 246, 16, 245, 0, 246, 17, 245, 0, 246, 16, + 1, 0, 246, 17, 1, 0, 246, 0, 247, 11, + 246, 0, 247, 11, 1, 0, 247, 0, 248, 12, + 247, 0, 248, 12, 1, 0, 248, 0, 249, 13, + 248, 0, 249, 13, 1, 0, 249, 0, 250, 14, + 249, 0, 250, 14, 1, 0, 250, 0, 251, 15, + 250, 0, 251, 15, 1, 0, 251, 0, 251, 87, + 257, 88, 252, 0, 251, 87, 88, 1, 0, 251, + 87, 1, 0, 251, 87, 257, 88, 1, 0, 252, + 0, 254, 0, 255, 256, 253, 0, 255, 256, 1, + 0, 119, 0, 231, 0, 233, 0, 91, 0, 92, + 0, 253, 0, 257, 0 +}; + +#endif + +#if YYDEBUG != 0 +static const short yyrline[] = { 0, + 251, 257, 259, 260, 261, 262, 263, 267, 269, 272, + 274, 275, 278, 280, 283, 287, 291, 295, 301, 303, + 305, 307, 312, 314, 317, 321, 326, 331, 333, 334, + 335, 336, 337, 338, 339, 342, 347, 353, 355, 358, + 361, 363, 367, 369, 372, 402, 404, 408, 421, 423, + 427, 433, 434, 436, 446, 451, 466, 470, 473, 476, + 479, 481, 483, 485, 489, 491, 493, 495, 499, 501, + 503, 510, 516, 521, 525, 528, 532, 534, 537, 539, + 540, 541, 544, 546, 547, 548, 552, 555, 567, 570, + 572, 576, 579, 586, 592, 600, 602, 606, 608, 610, + 614, 616, 621, 628, 640, 644, 647, 649, 651, 653, + 655, 657, 659, 661, 668, 671, 673, 678, 680, 684, + 689, 694, 698, 703, 708, 710, 717, 718, 719, 723, + 725, 726, 730, 732, 733, 738, 743, 749, 761, 766, + 772, 777, 786, 788, 791, 793, 794, 795, 799, 801, + 804, 805, 809, 816, 826, 830, 833, 836, 839, 842, + 845, 848, 851, 853, 857, 863, 868, 870, 874, 877, + 881, 883, 886, 888, 889, 890, 893, 897, 903, 908, + 913, 917, 921, 927, 929, 930, 935, 938, 941, 948, + 950, 953, 955, 957, 960, 964, 967, 971, 973, 975, + 977, 979, 981, 991, 993, 995, 997, 999, 1003, 1006, + 1008, 1010, 1012, 1014, 1016, 1018, 1019, 1021, 1023, 1027, + 1032, 1043, 1050, 1054, 1065, 1075, 1081, 1087, 1093, 1095, + 1097, 1099, 1101, 1103, 1105, 1107, 1109, 1113, 1115, 1119, + 1123, 1127, 1131, 1132, 1138, 1141, 1143, 1145, 1149, 1154, + 1159, 1161, 1163, 1165, 1169, 1171, 1172, 1173, 1176, 1178, + 1181, 1186, 1188, 1191, 1193, 1194, 1196, 1198, 1202, 1210, + 1213, 1215, 1217, 1221, 1226, 1235, 1240, 1243, 1250, 1252, + 1254, 1258, 1261, 1270, 1277, 1279, 1283, 1296, 1298, 1304, + 1310, 1314, 1316, 1320, 1323, 1325, 1329, 1332, 1334, 1336, + 1340, 1343, 1345, 1347, 1351, 1354, 1356, 1358, 1362, 1364, + 1366, 1370, 1372, 1374, 1376, 1378, 1382, 1389, 1391, 1392, + 1393, 1397, 1399, 1402, 1404, 1406, 1408, 1412, 1414, 1419, + 1421, 1424, 1426, 1428, 1430, 1431, 1432, 1433, 1437, 1438, + 1439, 1443, 1444, 1446, 1448, 1450, 1454, 1460, 1468, 1470, + 1475, 1476, 1477, 1478, 1479, 1481, 1483, 1485, 1487, 1489, + 1493, 1495, 1498, 1504, 1509, 1513, 1516, 1518, 1520, 1524, + 1526, 1528, 1530, 1534, 1537, 1541, 1547, 1549, 1557, 1560, + 1562, 1566, 1569, 1576, 1580, 1583, 1585, 1590, 1595, 1603, + 1615, 1617, 1621, 1624, 1626, 1631, 1636, 1641, 1648, 1650, + 1651, 1652, 1655, 1660, 1665, 1667, 1668, 1670, 1672, 1673, + 1675, 1679, 1682, 1686, 1689, 1693, 1695, 1697, 1699, 1700, + 1702, 1706, 1714, 1716, 1718, 1730, 1732, 1738, 1740, 1742, + 1746, 1748, 1753, 1758, 1763, 1765, 1767, 1771, 1773, 1778, + 1783, 1785, 1789, 1791, 1796, 1801, 1806, 1808, 1810, 1814, + 1816, 1821, 1826, 1831, 1836, 1837, 1839, 1841, 1843, 1845, + 1849, 1851, 1856, 1861, 1863, 1867, 1869, 1874, 1878, 1880, + 1885, 1889, 1891, 1896, 1900, 1902, 1907, 1911, 1913, 1918, + 1922, 1924, 1925, 1931, 1933, 1937, 1939, 1942, 1945, 1953, + 1955, 1956, 1959, 1961, 1964, 1968 +}; +#endif + + +#if YYDEBUG != 0 || defined (YYERROR_VERBOSE) + +static const char * const yytname[] = { "$","error","$undefined.","PLUS_TK", +"MINUS_TK","MULT_TK","DIV_TK","REM_TK","LS_TK","SRS_TK","ZRS_TK","AND_TK","XOR_TK", +"OR_TK","BOOL_AND_TK","BOOL_OR_TK","EQ_TK","NEQ_TK","GT_TK","GTE_TK","LT_TK", +"LTE_TK","PLUS_ASSIGN_TK","MINUS_ASSIGN_TK","MULT_ASSIGN_TK","DIV_ASSIGN_TK", +"REM_ASSIGN_TK","LS_ASSIGN_TK","SRS_ASSIGN_TK","ZRS_ASSIGN_TK","AND_ASSIGN_TK", +"XOR_ASSIGN_TK","OR_ASSIGN_TK","PUBLIC_TK","PRIVATE_TK","PROTECTED_TK","STATIC_TK", +"FINAL_TK","SYNCHRONIZED_TK","VOLATILE_TK","TRANSIENT_TK","NATIVE_TK","PAD_TK", +"ABSTRACT_TK","MODIFIER_TK","DECR_TK","INCR_TK","DEFAULT_TK","IF_TK","THROW_TK", +"BOOLEAN_TK","DO_TK","IMPLEMENTS_TK","THROWS_TK","BREAK_TK","IMPORT_TK","ELSE_TK", +"INSTANCEOF_TK","RETURN_TK","VOID_TK","CATCH_TK","INTERFACE_TK","CASE_TK","EXTENDS_TK", +"FINALLY_TK","SUPER_TK","WHILE_TK","CLASS_TK","SWITCH_TK","CONST_TK","TRY_TK", +"FOR_TK","NEW_TK","CONTINUE_TK","GOTO_TK","PACKAGE_TK","THIS_TK","BYTE_TK","SHORT_TK", +"INT_TK","LONG_TK","CHAR_TK","INTEGRAL_TK","FLOAT_TK","DOUBLE_TK","FP_TK","ID_TK", +"REL_QM_TK","REL_CL_TK","NOT_TK","NEG_TK","ASSIGN_ANY_TK","ASSIGN_TK","OP_TK", +"CP_TK","OCB_TK","CCB_TK","OSB_TK","CSB_TK","SC_TK","C_TK","DOT_TK","STRING_LIT_TK", +"CHAR_LIT_TK","INT_LIT_TK","FP_LIT_TK","TRUE_TK","FALSE_TK","BOOL_LIT_TK","NULL_TK", +"goal","literal","type","primitive_type","reference_type","class_or_interface_type", +"class_type","interface_type","array_type","name","simple_name","qualified_name", +"identifier","compilation_unit","import_declarations","type_declarations","package_declaration", +"import_declaration","single_type_import_declaration","type_import_on_demand_declaration", +"type_declaration","modifiers","class_declaration","@1","@2","super","interfaces", +"interface_type_list","class_body","class_body_declarations","class_body_declaration", +"class_member_declaration","field_declaration","variable_declarators","variable_declarator", +"variable_declarator_id","variable_initializer","method_declaration","@3","method_header", +"method_declarator","formal_parameter_list","formal_parameter","throws","class_type_list", +"method_body","static_initializer","static","constructor_declaration","constructor_declarator", +"constructor_body","explicit_constructor_invocation","this_or_super","interface_declaration", +"@4","@5","@6","@7","extends_interfaces","interface_body","interface_member_declarations", +"interface_member_declaration","constant_declaration","abstract_method_declaration", +"array_initializer","variable_initializers","block","@8","block_statements", +"block_statement","local_variable_declaration_statement","local_variable_declaration", +"statement","statement_nsi","statement_without_trailing_substatement","empty_statement", +"label_decl","labeled_statement","labeled_statement_nsi","expression_statement", +"statement_expression","if_then_statement","if_then_else_statement","if_then_else_statement_nsi", +"switch_statement","switch_block","switch_block_statement_groups","switch_block_statement_group", +"switch_labels","switch_label","while_expression","while_statement","while_statement_nsi", +"do_statement_begin","do_statement","for_statement","for_statement_nsi","for_header", +"for_begin","for_init","for_update","statement_expression_list","break_statement", +"continue_statement","return_statement","throw_statement","synchronized_statement", +"synchronized","try_statement","catches","catch_clause","finally","primary", +"primary_no_new_array","class_instance_creation_expression","something_dot_new", +"argument_list","array_creation_expression","dim_exprs","dim_expr","dims","field_access", +"method_invocation","array_access","postfix_expression","post_increment_expression", +"post_decrement_expression","unary_expression","pre_increment_expression","pre_decrement_expression", +"unary_expression_not_plus_minus","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", +"assignment","left_hand_side","assignment_operator","expression","constant_expression", NULL +}; +#endif + +static const short yyr1[] = { 0, + 110, 111, 111, 111, 111, 111, 111, 112, 112, 113, + 113, 113, 114, 114, 115, 116, 117, 118, 118, 118, + 118, 118, 119, 119, 120, 121, 122, 123, 123, 123, + 123, 123, 123, 123, 123, 124, 124, 125, 125, 126, + 126, 126, 127, 127, 128, 128, 128, 129, 129, 129, + 130, 130, 130, 130, 131, 131, 133, 132, 134, 132, + 132, 132, 132, 132, 135, 135, 135, 135, 136, 136, + 136, 137, 137, 137, 138, 138, 139, 139, 140, 140, + 140, 140, 141, 141, 141, 141, 142, 142, 143, 143, + 143, 144, 144, 144, 144, 145, 145, 145, 145, 145, + 146, 146, 148, 147, 147, 149, 149, 149, 149, 149, + 149, 149, 149, 149, 150, 150, 150, 150, 150, 151, + 151, 151, 152, 152, 152, 152, 153, 153, 153, 154, + 154, 154, 155, 155, 155, 156, 156, 157, 158, 158, + 158, 158, 159, 159, 160, 160, 160, 160, 161, 161, + 161, 161, 162, 162, 164, 163, 165, 163, 166, 163, + 167, 163, 163, 163, 168, 168, 168, 168, 169, 169, + 170, 170, 171, 171, 171, 171, 172, 173, 173, 174, + 174, 174, 174, 175, 175, 175, 176, 177, 176, 178, + 178, 179, 179, 179, 180, 181, 181, 182, 182, 182, + 182, 182, 182, 183, 183, 183, 183, 183, 184, 184, + 184, 184, 184, 184, 184, 184, 184, 184, 184, 185, + 186, 187, 187, 188, 189, 189, 189, 189, 189, 189, + 189, 189, 189, 189, 189, 189, 189, 190, 190, 190, + 190, 190, 190, 190, 191, 191, 191, 191, 192, 193, + 194, 194, 194, 194, 195, 195, 195, 195, 196, 196, + 197, 198, 198, 199, 199, 199, 199, 199, 200, 201, + 201, 201, 201, 202, 203, 204, 205, 205, 205, 205, + 205, 206, 206, 207, 207, 207, 208, 209, 209, 209, + 209, 210, 210, 211, 211, 211, 212, 212, 212, 212, + 213, 213, 213, 213, 214, 214, 214, 214, 215, 215, + 215, 216, 216, 216, 216, 216, 217, 218, 218, 218, + 218, 219, 219, 220, 220, 220, 220, 221, 221, 222, + 222, 223, 223, 223, 223, 223, 223, 223, 223, 223, + 223, 223, 223, 223, 223, 223, 224, 224, 224, 224, + 224, 224, 224, 224, 224, 224, 224, 224, 224, 224, + 225, 225, 226, 226, 226, 227, 227, 227, 227, 227, + 227, 227, 227, 228, 228, 229, 229, 229, 230, 230, + 230, 231, 231, 231, 232, 232, 232, 232, 232, 232, + 232, 232, 233, 233, 233, 233, 233, 233, 234, 234, + 234, 234, 235, 236, 237, 237, 237, 237, 237, 237, + 237, 238, 238, 239, 239, 240, 240, 240, 240, 240, + 240, 241, 241, 241, 241, 241, 241, 241, 241, 241, + 242, 242, 242, 242, 242, 242, 242, 243, 243, 243, + 243, 243, 244, 244, 244, 244, 244, 244, 244, 245, + 245, 245, 245, 245, 245, 245, 245, 245, 245, 245, + 246, 246, 246, 246, 246, 247, 247, 247, 248, 248, + 248, 249, 249, 249, 250, 250, 250, 251, 251, 251, + 252, 252, 252, 252, 252, 253, 253, 254, 254, 255, + 255, 255, 256, 256, 257, 258 +}; + +static const short yyr2[] = { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, + 3, 3, 1, 1, 1, 3, 1, 0, 1, 1, + 1, 2, 2, 2, 3, 1, 2, 1, 2, 3, + 2, 3, 1, 1, 3, 2, 3, 5, 4, 5, + 1, 1, 1, 1, 1, 2, 0, 7, 0, 6, + 3, 2, 3, 4, 0, 2, 3, 2, 0, 2, + 2, 1, 3, 3, 2, 3, 1, 2, 1, 1, + 1, 1, 1, 1, 1, 1, 3, 4, 1, 3, + 3, 1, 3, 3, 4, 1, 3, 2, 3, 3, + 1, 1, 0, 3, 2, 3, 3, 4, 4, 2, + 3, 2, 3, 2, 3, 4, 3, 3, 3, 1, + 3, 3, 2, 3, 2, 3, 0, 2, 2, 1, + 3, 3, 1, 2, 1, 2, 3, 1, 3, 4, + 4, 5, 3, 4, 2, 3, 3, 4, 4, 5, + 7, 6, 1, 1, 0, 4, 0, 5, 0, 5, + 0, 6, 3, 4, 2, 3, 2, 3, 2, 3, + 1, 2, 1, 1, 1, 1, 1, 2, 2, 2, + 3, 3, 4, 1, 3, 3, 2, 0, 4, 1, + 2, 1, 1, 1, 2, 2, 3, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 3, 4, + 4, 5, 4, 5, 6, 7, 6, 1, 1, 1, + 1, 1, 1, 1, 5, 2, 3, 4, 7, 7, + 5, 2, 3, 5, 2, 3, 3, 4, 1, 2, + 2, 1, 2, 3, 2, 2, 3, 2, 4, 2, + 2, 3, 4, 2, 1, 7, 7, 6, 3, 5, + 4, 7, 6, 2, 2, 3, 2, 0, 1, 1, + 2, 0, 1, 1, 3, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 3, 2, + 3, 5, 5, 2, 4, 3, 1, 3, 3, 4, + 2, 1, 2, 5, 2, 4, 3, 2, 2, 1, + 1, 1, 1, 3, 1, 1, 1, 1, 3, 3, + 3, 3, 3, 3, 3, 3, 5, 4, 6, 5, + 4, 5, 5, 6, 3, 3, 4, 5, 2, 3, + 3, 3, 1, 3, 3, 3, 3, 4, 4, 4, + 4, 3, 3, 1, 2, 3, 3, 2, 2, 3, + 3, 3, 3, 2, 3, 4, 5, 6, 5, 6, + 4, 4, 4, 4, 3, 4, 3, 4, 1, 1, + 1, 1, 2, 2, 1, 1, 2, 2, 1, 2, + 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, + 2, 5, 4, 4, 5, 4, 2, 5, 4, 5, + 1, 3, 3, 3, 3, 3, 3, 1, 3, 3, + 3, 3, 1, 3, 3, 3, 3, 3, 3, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 1, 3, 3, 3, 3, 1, 3, 3, 1, 3, + 3, 1, 3, 3, 1, 3, 3, 1, 3, 3, + 1, 5, 4, 3, 5, 1, 1, 3, 3, 1, + 1, 1, 1, 1, 1, 1 +}; + +static const short yydefact[] = { 0, + 54, 55, 0, 0, 0, 0, 53, 1, 0, 0, + 0, 36, 43, 44, 38, 0, 51, 52, 46, 27, + 0, 23, 24, 25, 0, 62, 0, 41, 0, 0, + 37, 39, 0, 0, 56, 0, 0, 47, 45, 0, + 163, 0, 0, 159, 63, 0, 69, 42, 40, 0, + 0, 0, 61, 0, 49, 0, 26, 167, 17, 165, + 15, 0, 156, 0, 0, 68, 16, 0, 0, 59, + 164, 0, 161, 64, 69, 50, 48, 12, 0, 10, + 11, 169, 0, 8, 9, 13, 14, 15, 0, 175, + 177, 0, 176, 0, 171, 173, 174, 168, 166, 160, + 67, 71, 72, 70, 0, 158, 0, 57, 112, 0, + 127, 110, 0, 0, 89, 92, 127, 0, 0, 0, + 114, 0, 0, 179, 178, 170, 172, 0, 0, 60, + 162, 0, 0, 0, 0, 107, 98, 87, 0, 0, + 0, 0, 106, 21, 18, 22, 20, 19, 113, 127, + 111, 0, 127, 74, 73, 55, 188, 75, 23, 0, + 85, 0, 77, 79, 83, 84, 0, 80, 0, 81, + 127, 86, 82, 58, 118, 115, 0, 0, 0, 120, + 129, 130, 128, 119, 117, 91, 0, 90, 94, 0, + 0, 0, 0, 0, 0, 0, 333, 0, 0, 0, + 0, 6, 5, 2, 3, 4, 7, 332, 0, 400, + 0, 102, 399, 330, 335, 0, 331, 336, 337, 338, + 416, 401, 402, 431, 405, 406, 409, 419, 438, 443, + 450, 461, 466, 469, 472, 475, 478, 481, 486, 495, + 487, 0, 101, 99, 97, 100, 109, 88, 108, 187, + 0, 0, 127, 76, 78, 105, 0, 136, 0, 125, + 123, 0, 116, 0, 0, 410, 400, 336, 338, 407, + 411, 408, 415, 414, 413, 412, 0, 384, 0, 0, + 0, 16, 0, 420, 417, 421, 418, 427, 0, 400, + 0, 180, 0, 184, 0, 0, 0, 0, 0, 95, + 0, 0, 359, 0, 404, 403, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 493, 494, 0, + 0, 55, 0, 0, 275, 0, 0, 0, 0, 0, + 0, 0, 0, 333, 0, 220, 0, 8, 400, 0, + 0, 194, 0, 209, 0, 190, 192, 0, 193, 198, + 210, 0, 199, 211, 0, 200, 201, 212, 0, 202, + 0, 213, 203, 288, 0, 214, 215, 216, 218, 217, + 0, 219, 244, 243, 0, 241, 242, 239, 240, 238, + 143, 0, 0, 135, 104, 133, 137, 0, 139, 126, + 124, 122, 121, 132, 131, 346, 341, 0, 383, 373, + 372, 355, 0, 366, 374, 0, 367, 0, 356, 0, + 0, 0, 0, 0, 0, 343, 334, 182, 181, 0, + 345, 340, 385, 0, 363, 395, 0, 344, 339, 361, + 342, 362, 382, 397, 0, 360, 0, 435, 432, 436, + 433, 437, 434, 441, 439, 442, 440, 447, 444, 448, + 445, 449, 446, 457, 452, 459, 454, 456, 451, 458, + 453, 460, 0, 455, 464, 462, 465, 463, 468, 467, + 471, 470, 474, 473, 477, 476, 480, 479, 484, 0, + 0, 489, 488, 227, 228, 226, 246, 0, 310, 0, + 299, 297, 0, 307, 305, 0, 271, 0, 252, 0, + 321, 0, 285, 0, 303, 301, 0, 0, 196, 0, + 0, 223, 221, 0, 0, 189, 191, 195, 317, 400, + 222, 225, 270, 0, 400, 0, 290, 294, 287, 0, + 0, 314, 0, 144, 140, 134, 145, 400, 0, 0, + 0, 141, 391, 392, 0, 378, 379, 0, 375, 368, + 0, 371, 369, 370, 357, 348, 0, 429, 423, 426, + 0, 0, 424, 186, 183, 185, 386, 0, 396, 393, + 0, 398, 394, 351, 0, 483, 0, 247, 0, 311, + 309, 300, 298, 308, 306, 272, 0, 253, 0, 0, + 0, 318, 322, 319, 286, 304, 302, 334, 0, 197, + 229, 0, 0, 0, 291, 0, 279, 0, 0, 316, + 0, 142, 0, 146, 0, 0, 147, 389, 0, 377, + 376, 381, 380, 350, 358, 347, 428, 422, 430, 425, + 365, 364, 387, 0, 352, 353, 485, 482, 248, 0, + 273, 269, 0, 325, 0, 329, 328, 323, 320, 233, + 0, 230, 231, 0, 0, 296, 295, 281, 0, 293, + 0, 315, 0, 0, 148, 0, 0, 390, 349, 388, + 354, 0, 245, 0, 198, 0, 205, 206, 0, 207, + 208, 0, 254, 0, 251, 327, 0, 234, 0, 0, + 232, 0, 0, 280, 0, 313, 312, 0, 149, 0, + 0, 0, 224, 274, 0, 0, 0, 255, 0, 259, + 0, 262, 326, 0, 237, 235, 0, 0, 278, 0, + 0, 0, 150, 0, 249, 0, 0, 268, 265, 266, + 496, 0, 257, 260, 0, 256, 0, 263, 324, 236, + 276, 277, 152, 0, 0, 0, 0, 267, 264, 258, + 151, 0, 0, 0, 0, 283, 0, 250, 282, 0, + 0, 0 +}; + +static const short yydefgoto[] = { 770, + 208, 347, 209, 85, 86, 68, 60, 87, 210, 22, + 23, 24, 8, 9, 10, 11, 12, 13, 14, 15, + 351, 352, 132, 105, 47, 70, 104, 130, 162, 163, + 164, 91, 114, 115, 116, 211, 166, 257, 92, 111, + 179, 180, 136, 183, 395, 168, 169, 170, 171, 399, + 549, 353, 18, 43, 72, 65, 107, 44, 63, 94, + 95, 96, 97, 212, 295, 354, 251, 747, 356, 357, + 358, 359, 684, 360, 361, 362, 363, 687, 364, 365, + 366, 367, 688, 368, 695, 719, 720, 721, 722, 369, + 370, 690, 371, 372, 373, 691, 374, 375, 539, 669, + 670, 376, 377, 378, 379, 380, 381, 382, 602, 603, + 604, 213, 214, 215, 216, 434, 217, 414, 415, 416, + 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, + 238, 239, 240, 241, 242, 330, 435, 742 +}; + +static const short yypact[] = { 353, +-32768,-32768, 325, -41, 376, 398,-32768,-32768, 164, 528, + 436,-32768,-32768,-32768,-32768, 494,-32768,-32768,-32768,-32768, + 10,-32768,-32768,-32768, 18,-32768, 297,-32768, 11, 576, +-32768,-32768, 445, 598,-32768, -41, 428,-32768,-32768, 690, +-32768, 470, -13, -46,-32768, 495, 82,-32768,-32768, -41, + 612, 328,-32768, 381,-32768, 28,-32768,-32768,-32768,-32768, + -36, 1021,-32768, 531, -13,-32768,-32768, 232, 577,-32768, +-32768, -13, -46,-32768, 82,-32768,-32768,-32768, 590,-32768, +-32768,-32768, 592, 2,-32768,-32768, 170, -7, 916,-32768, +-32768, 92,-32768, 1055,-32768,-32768,-32768,-32768,-32768,-32768, +-32768,-32768,-32768, 172, 202,-32768, -13,-32768,-32768, 262, + -1,-32768, 424, -75,-32768, 504, -1, 9, 86, 278, +-32768, 615, 617,-32768,-32768,-32768,-32768, 637, 936,-32768, +-32768, 202, 729, 653, 117,-32768,-32768,-32768, 660, 2333, + 132, 384,-32768,-32768,-32768,-32768,-32768,-32768,-32768, -1, +-32768, 655, -1,-32768,-32768, 337, 377,-32768, 417, 916, +-32768, 1001,-32768,-32768,-32768,-32768, 47,-32768, 406,-32768, + 472,-32768,-32768,-32768,-32768,-32768, 667, 903, 551,-32768, +-32768,-32768, 442,-32768,-32768,-32768, 460,-32768,-32768, 3080, + 3145, 3196, 3261, 466, 21, 497,-32768, 3312, 3377, 3428, + 5442,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 543, 915, + 99,-32768, 548, 560,-32768, 712,-32768, 770,-32768, 836, + 888,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 619, 945, + 1019, 937, 935, 669, 676, 694, 714, 258,-32768,-32768, +-32768, 872,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, + 2125, 731, 472,-32768,-32768,-32768, 128, 634, 668,-32768, + 873, 719,-32768, 585, 721,-32768, 673,-32768,-32768,-32768, +-32768,-32768,-32768,-32768,-32768,-32768, 25,-32768, 724, 992, + 643, 643, 290,-32768,-32768,-32768,-32768,-32768, 746, 962, + 208,-32768, 654,-32768, 358, 331, 5509, 3493, 622,-32768, + 427, 3544,-32768, 393,-32768,-32768, 3609, 3660, 3725, 3776, + 3841, 3892, 3957, 4008, 4073, 4124, 4189, 4240, 525, 4305, + 4356, 4421, 4472, 4537, 4588, 4653, 2384,-32768,-32768, 4704, + 510, 415, 416, 4769,-32768, 182, 2449, 13, 418, 426, + 26, 450, 204, 679, 5741,-32768, -41, 618, 844, 448, + 827,-32768, 684,-32768, 1785,-32768,-32768, 685,-32768,-32768, +-32768, 2193,-32768,-32768, 689,-32768,-32768,-32768, 2193,-32768, + 2193,-32768,-32768, 5792, 697,-32768,-32768,-32768,-32768,-32768, + 469,-32768, 702, 711, 888, 947, 965,-32768,-32768,-32768, +-32768, 759, 668,-32768,-32768, 728,-32768, 1853, 732,-32768, + 873,-32768,-32768,-32768,-32768,-32768,-32768, 123, 740,-32768, +-32768,-32768, 2500, 643,-32768, 493, 643, 493,-32768, 2565, + 4820, 166, -30, 2616, 308,-32768, 1180,-32768,-32768, 1645, +-32768,-32768,-32768, 781,-32768,-32768, 239,-32768,-32768,-32768, +-32768,-32768, 772,-32768, 244,-32768, 5560,-32768,-32768,-32768, +-32768,-32768,-32768,-32768, 619,-32768, 619,-32768, 945,-32768, + 945,-32768, 945,-32768, 1019,-32768, 1019,-32768, 1019,-32768, + 1019,-32768, 2,-32768,-32768, 937,-32768, 937,-32768, 935, +-32768, 669,-32768, 676,-32768, 694,-32768, 714,-32768, 766, + 784,-32768,-32768,-32768,-32768,-32768,-32768, 4885,-32768, 143, +-32768,-32768, 153,-32768,-32768, 180,-32768, 4936,-32768, 5001, +-32768, 681,-32768, 5350,-32768,-32768, 235, 242, 783, 2681, + 620,-32768,-32768, -41, 2732,-32768,-32768,-32768,-32768, 1070, +-32768,-32768,-32768, 821, 984, 903,-32768,-32768,-32768, 104, + 2797,-32768, 5052,-32768, 802,-32768,-32768, 1037, 1921, 812, + 1989,-32768,-32768,-32768, 5625,-32768,-32768, 259,-32768, 826, + 295,-32768, 826,-32768,-32768, 202, 61,-32768,-32768,-32768, + 5117, 817,-32768,-32768,-32768,-32768,-32768, 5168,-32768,-32768, + 5676,-32768,-32768, 202, 785,-32768, 5233,-32768, 252,-32768, +-32768,-32768,-32768,-32768,-32768,-32768, 253,-32768, 845, 471, + 46, 681,-32768,-32768,-32768,-32768,-32768,-32768, 473, 783, +-32768, 941, 122, 851,-32768, 5484,-32768, 5375, 855, 865, + 867,-32768, 645,-32768, 2057, 2848,-32768,-32768, 792,-32768, +-32768,-32768,-32768,-32768,-32768, 202,-32768,-32768,-32768,-32768, +-32768,-32768,-32768, 814,-32768, 202,-32768,-32768,-32768, 2259, +-32768,-32768, 87,-32768, 788,-32768,-32768,-32768,-32768,-32768, + 2913,-32768,-32768, 972, 5741,-32768,-32768,-32768, 885, 884, + 5417,-32768, 206, 478,-32768, 245, 134,-32768,-32768,-32768, +-32768, 481,-32768, 931, 934, 2259,-32768,-32768, 2259,-32768, +-32768, 897,-32768, 733,-32768, 905, 910,-32768, 1016, 138, +-32768, 929, 2193,-32768, 939,-32768,-32768, 2964,-32768, 257, + 4885, 2193,-32768,-32768, 3029, 167, 5284,-32768, 739,-32768, + 1484,-32768,-32768, 406,-32768,-32768, 1024, 944,-32768, 2193, + 273, 150,-32768, 269,-32768, 5375, 948,-32768,-32768,-32768, +-32768, 212,-32768,-32768, 1571,-32768, 1717,-32768,-32768,-32768, +-32768,-32768,-32768, 276, 2259, 946, 5417,-32768,-32768,-32768, +-32768, 974, 2259, 955, 2259,-32768, 2259,-32768,-32768, 1038, + 1052,-32768 +}; + +static const short yypgoto[] = {-32768, +-32768, -58, 14, 737, 4, -99, 674,-32768, -3, 677, +-32768, 79,-32768, 1047, 760,-32768, 266,-32768,-32768, 881, + 7, 23,-32768,-32768, 1007, 997,-32768, -131,-32768, 912, +-32768, 281, -121, 928, 431, -195,-32768,-32768, 408, 509, + 832, -259, -73,-32768,-32768,-32768,-32768,-32768, 918, 686, +-32768, 700, -34,-32768,-32768,-32768,-32768, 1040, 508,-32768, + 1006,-32768,-32768, 500,-32768, -120,-32768, -221, -340,-32768, + 727, -299, 101, -526,-32768, -325,-32768,-32768,-32768, -336, +-32768,-32768,-32768,-32768,-32768,-32768, 389, 391, -666, -300, +-32768,-32768,-32768,-32768,-32768,-32768,-32768, -280,-32768, -297, + 741,-32768,-32768,-32768,-32768,-32768,-32768,-32768,-32768, 511, + 517,-32768,-32768, -31,-32768, -369,-32768, 813, 219, -269, + 1157, 133, 1187, 279, 423, 486, -20, 569, 607, -419, +-32768, 703, 819, 534, 699, 799, 801, 803, 800, 816, +-32768, 552, 815, 695,-32768,-32768, -51,-32768 +}; + + +#define YYLAST 5901 + + +static const short yytable[] = { 21, + 174, 152, 29, 83, 403, 294, 16, 573, 173, 144, + 38, 48, 418, 278, 527, 16, 16, 16, 41, 423, + 425, 278, 17, 138, 139, 406, 511, 93, 76, 355, + 123, 17, 17, 17, 182, 83, 16, 538, 61, 16, + 16, 173, 61, 143, 20, 59, 656, 256, 258, 67, + 567, 134, 17, 64, 748, 17, 17, 16, 88, 93, + 61, 635, 531, 571, 50, 61, 561, 59, 89, 533, + 83, 534, 59, 17, 177, 84, 247, 585, 748, 249, + 42, 62, 25, 27, 90, 88, 146, 693, 243, 120, + 88, 407, 124, 50, 172, 135, 283, 259, 118, 300, + 89, 123, 84, 83, 615, -154, 145, 84, 39, 49, + 40, 50, -155, 279, 52, 54, 90, 184, 57, 262, + 157, 279, 663, 685, 61, 88, 77, 172, 57, 88, + 61, 59, 244, 69, 663, 160, 396, 67, 726, 178, + 157, -103, 84, 590, 560, -103, 84, 563, 291, 243, + 726, 161, 640, 592, 636, 613, 88, 110, 88, 685, + 578, 113, 685, -30, 1, 405, 570, 738, 160, 270, + 272, 274, 276, 84, 88, 84, 551, 285, 287, 393, + 594, 694, 501, 147, 161, 629, 267, 267, 267, 267, + 125, 84, 61, 177, 267, 267, 290, -93, -93, 282, + 110, 113, -289, 616, 515, 177, 706, 2, 426, 281, + 527, 644, 758, 289, 185, 664, 553, 187, 3, 383, + 512, 578, 157, 554, 4, 519, 394, 710, 685, 245, + 5, 727, 101, 578, 576, 606, 685, 578, 685, 579, + 685, 591, 426, 754, 582, 662, 437, 349, 88, 578, + 445, 593, 649, 651, 739, 187, 677, 701, 178, 630, + 88, 61, 7, 557, 348, 84, 119, 20, 67, 649, + 178, 128, 326, 725, 31, 491, 750, 84, 595, 667, + 502, 538, 500, -66, 527, 506, 449, 451, 453, 20, + 419, 700, 524, 518, 304, 632, 129, 45, 31, 759, + 157, 427, 516, 267, 267, 267, 267, 267, 267, 267, + 267, 267, 267, 267, 267, 88, 267, 267, 267, 267, + 267, 267, 267, 383, 686, 19, -66, 625, 71, 350, + 383, 431, 473, 607, 538, 608, 580, 383, 732, 383, + 187, 583, 383, 709, 327, 650, 652, 88, -65, 689, + 683, 349, -28, 1, 133, 733, 631, 409, 530, 46, + 686, 558, 755, 686, 84, 530, 383, 530, 348, 692, + 535, 753, 437, 705, 761, 148, 26, 57, 243, 443, + 536, 74, 420, 384, 246, 689, 531, 348, 689, 533, + 42, -65, 633, 446, 548, 697, 2, 432, 28, 538, + 569, 572, 610, 729, 561, 692, 527, 3, 692, 165, + 20, 348, 735, 4, 503, -317, 497, 267, 507, 5, + 538, 517, -157, 267, 137, 187, 509, 6, 53, 686, + 752, -138, -65, 350, 634, -29, 1, 686, 756, 686, + 350, 686, 165, 46, -32, 1, 589, 350, 522, 350, + 513, 7, 645, 429, 689, 683, 597, 430, 599, 764, + 137, 20, 689, 729, 689, 735, 689, 752, 437, 542, + 58, 654, 250, 660, 692, -65, 350, 524, 660, 2, + 657, 497, 692, 20, 692, 447, 692, 384, 2, 619, + 3, 621, -25, -25, 384, 66, 4, 280, 442, 3, + 157, 384, 5, 384, 679, 4, 384, -317, 498, 252, + 508, 5, 20, 20, 681, -96, 133, 383, 510, 383, + -96, -96, -96, -96, 134, 472, 642, -31, 1, 385, + 384, 98, 88, -25, 7, 523, 167, 35, -25, -25, + -25, 265, 514, 7, -25, 349, 78, 349, -25, 84, + 638, -96, 707, -96, 36, 20, -96, -96, -96, -96, + 37, 543, 348, 655, 348, 661, 277, 267, 267, 167, + 708, 2, 100, 711, 78, -34, 1, 102, 80, 106, + 20, 81, 20, 267, 383, 402, 383, 201, 4, 561, + 109, 117, 112, 383, 5, 140, 177, -33, 1, 57, + 141, 142, 187, 749, 494, 495, 80, 261, 496, 81, + 20, -35, 1, 702, 131, 149, 20, 151, 383, 2, + 438, 349, 438, 307, 308, 309, 7, 350, 2, 350, + 150, 153, 559, 385, 78, 559, 4, 154, 348, 383, + 385, 2, 5, 296, 263, 438, 530, 385, 301, 385, + 264, 88, 385, 181, 383, 2, 302, 383, 4, 734, + 186, 178, 20, 737, 5, 741, 80, 260, 84, 81, + 20, 383, 4, 386, 7, 20, 385, 20, 5, 322, + 383, 384, 530, 384, 609, 530, 439, 323, 439, 383, + 55, 440, 401, 440, 56, 441, 7, 441, 383, 530, + 20, 57, 20, 350, 383, 20, 324, 20, 530, 674, + 7, 439, 303, 383, 118, 383, 440, 349, 296, 400, + 441, 404, 20, 383, 408, 383, 530, 325, 350, 175, + 20, 383, 397, 383, 348, 383, 387, 99, 20, 413, + 600, 349, 103, 349, 601, 20, -335, -335, 384, 428, + 384, 530, 20, 248, 139, -337, -337, 384, 348, 530, + 348, 530, 398, 530, 350, 297, 586, 350, 30, 298, + 34, -153, 2, 299, 2, 20, 525, 386, 78, 716, + 78, 350, 384, 528, 386, 716, 713, 532, 696, 714, + 350, 386, 51, 386, 717, 541, 386, 20, -335, 350, + 717, 155, -335, 384, 20, 159, 20, -337, 350, 20, + 80, -337, 80, 81, 20, 81, 20, 639, 384, 388, + 386, 384, 176, 350, 391, 350, 546, 385, 718, 385, + 552, 2, 555, 350, 743, 384, 159, 78, 159, 421, + 387, 350, 422, 350, 384, 350, 296, 387, 465, 467, + 469, 471, 544, 384, 387, 762, 387, 389, 264, 387, + -491, -491, 384, 766, 581, 768, 78, 769, 384, 80, + 35, 587, 81, 20, 577, 194, 78, 384, 646, 384, + 578, 195, 139, 387, 578, 678, 614, 384, 196, 384, + 32, 578, 197, 37, 385, 384, 385, 384, 80, 384, + 622, 81, 20, 385, 626, 198, 199, 680, 80, 200, + 32, 81, 20, 578, 32, 562, 121, 564, 202, 203, + 204, 205, 561, 388, 206, 207, -492, -492, 385, -15, + 388, 32, 305, 306, -490, -490, 297, 388, 653, 388, + 520, 662, 388, 665, 521, 390, 35, 310, 311, 385, + 320, 321, 78, 671, 315, 316, 317, 318, 672, 35, + 673, 389, 328, 329, 385, 78, 388, 385, 389, 141, + 142, 386, 701, 386, 122, 389, 36, 389, 703, 156, + 389, 385, 37, 616, 80, 78, 712, 81, 20, -204, + 385, -401, -401, 319, 79, 715, 4, 80, 723, 385, + 81, 20, 5, 724, 389, -490, -490, 297, 385, -402, + -402, 298, 455, 457, 385, 299, 725, 80, 476, 478, + 81, 20, 728, 385, 750, 385, 312, 313, 314, 765, + 157, 158, 730, 385, 387, 385, 387, 771, 386, 763, + 386, 385, 751, 385, 156, 385, 757, 386, 767, 390, + 78, 772, -490, -490, 297, 474, 390, 33, 424, 79, + 75, 4, 299, 390, 2, 390, 188, 5, 390, -15, + 78, 108, 386, 255, -490, -490, 297, 253, 545, 79, + 520, 4, 80, 392, 299, 81, 20, 5, 410, 411, + 412, 73, 390, 386, 417, 157, 254, 550, 2, 127, + 537, 387, 80, 387, 78, 81, 20, 744, 386, 745, + 387, 386, 658, 79, 540, 4, 82, 388, 659, 388, + 480, 5, -15, 482, 486, 386, 484, -490, -490, 297, + 459, 461, 463, 520, 386, 387, 80, 623, 648, 81, + 20, 488, 0, 386, 493, 0, 0, 0, 0, 0, + 126, 0, 386, 0, 0, 389, 387, 389, 386, 0, + -490, -490, 297, 0, 0, 0, 298, 386, 0, 386, + 521, 387, 0, 0, 387, 0, 0, 386, 0, 386, + 0, 0, 0, 0, 388, 386, 388, 386, 387, 386, + 0, 0, 0, 388, 0, 0, 0, 387, 0, 0, + 0, 0, 0, 0, 0, 0, 387, 0, 0, 0, + 0, 0, 0, 0, 0, 387, 0, 0, 388, 0, + 0, 387, 389, 0, 389, 0, 0, 0, 0, 78, + 387, 389, 387, 0, 0, 0, 0, 0, 194, 388, + 387, 0, 387, 390, 195, 390, 0, 0, 387, 0, + 387, 196, 387, 0, 388, 197, 389, 388, 0, 0, + 0, 80, 0, 0, 81, 20, 0, 0, 198, 199, + 0, 388, 200, 0, 0, 0, 0, 389, 0, 0, + 388, 202, 203, 204, 205, 0, 0, 206, 207, 388, + 0, 0, 389, 0, 0, 389, 0, 0, 388, 0, + 0, 0, 0, 0, 388, 0, 0, 0, 0, 389, + 390, 0, 390, 388, 0, 388, 0, 0, 389, 390, + 0, 0, 0, 388, 0, 388, 0, 389, 0, 0, + 0, 388, 0, 388, 0, 388, 389, 0, 0, 0, + 0, 0, 389, 0, 390, 0, 268, 268, 268, 268, + 0, 389, 0, 389, 268, 268, 0, 0, 0, 0, + 0, 389, 0, 389, 0, 390, 0, 0, 0, 389, + 0, 389, 0, 389, 0, 0, 269, 269, 269, 269, + 390, 0, 0, 390, 269, 269, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 390, 0, 0, + 0, 0, 0, 0, 0, 0, 390, 0, 0, 0, + 0, 0, 0, 0, 0, 390, 0, 0, 0, 0, + 0, 0, 0, 0, 390, 0, 0, 0, 0, 0, + 390, 0, 0, 0, 0, 0, 0, 0, 0, 390, + 0, 390, 0, 0, 0, 0, 0, 0, 0, 390, + 0, 390, 0, 0, 0, 0, 0, 390, 0, 390, + 0, 390, 0, 268, 268, 268, 268, 268, 268, 268, + 268, 268, 268, 268, 268, 0, 268, 268, 268, 268, + 268, 268, 268, 0, 331, 0, 0, 0, 0, 0, + 0, 0, 0, 269, 269, 269, 269, 269, 269, 269, + 269, 269, 269, 269, 269, 0, 269, 269, 269, 269, + 269, 269, 269, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 332, 192, 193, + 716, 333, 334, 78, 335, 0, 0, 336, 0, 0, + 0, 337, 194, 0, 0, 717, 0, 0, 338, 339, + 5, 340, 0, 341, 342, 196, 343, 0, 0, 344, + 0, 0, 0, 0, 0, 80, 0, 0, 81, 20, + 0, 331, 0, 0, 0, 0, 345, 268, 157, 746, + 0, 0, 346, 268, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 269, 0, 0, + 0, 0, 0, 269, 332, 192, 193, 716, 333, 334, + 78, 335, 0, 0, 336, 0, 0, 0, 337, 194, + 0, 0, 717, 0, 0, 338, 339, 5, 340, 0, + 341, 342, 196, 343, 0, 574, 344, 190, 191, 0, + 0, 0, 80, 0, 0, 81, 20, 0, 0, 0, + 0, 0, 0, 345, 0, 157, 760, 0, 0, 346, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 192, + 193, 0, 0, 0, 78, 0, 0, 0, 0, 0, + 0, 0, 0, 194, 0, 0, 0, 0, 0, 195, + 0, 0, 0, 0, 0, 0, 196, 331, 0, 0, + 197, 0, 0, 0, 0, 0, 80, 268, 268, 81, + 20, 0, 0, 198, 199, 0, 0, 200, 0, 201, + 575, 0, 0, 268, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 0, 0, 0, 269, 269, 0, + 332, 192, 193, -261, 333, 334, 78, 335, 0, 0, + 336, 0, 0, 269, 337, 194, 0, 0, -261, 0, + 0, 338, 339, 5, 340, 331, 341, 342, 196, 343, + 0, 0, 344, 0, 0, 0, 0, 0, 80, 0, + 0, 81, 20, 0, 0, 0, 0, 0, 0, 345, + 0, 157, -261, 0, 0, 346, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 0, 0, 332, 192, + 193, 0, 333, 334, 78, 335, 0, 0, 336, 0, + 0, 0, 337, 194, 0, 0, 0, 0, 0, 338, + 339, 5, 340, 331, 341, 342, 196, 343, 0, 0, + 344, 0, 0, 0, 0, 0, 80, 0, 0, 81, + 20, 0, 0, 0, 0, 0, 0, 345, 0, 157, + 526, 0, 0, 346, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 0, 0, 332, 192, 193, 0, + 333, 334, 78, 335, 0, 0, 336, 0, 0, 0, + 337, 194, 0, 0, 0, 0, 0, 338, 339, 5, + 340, 331, 341, 342, 196, 343, 0, 0, 344, 0, + 0, 0, 0, 0, 80, 0, 0, 81, 20, 0, + 0, 0, 0, 0, 0, 345, 0, 157, 547, 0, + 0, 346, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 0, 0, 332, 192, 193, 0, 333, 334, + 78, 335, 0, 0, 336, 0, 0, 0, 337, 194, + 0, 0, 0, 0, 0, 338, 339, 5, 340, 331, + 341, 342, 196, 343, 0, 0, 344, 0, 0, 0, + 0, 0, 80, 0, 0, 81, 20, 0, 0, 0, + 0, 0, 0, 345, 0, 157, 624, 0, 0, 346, + 0, 0, 202, 203, 204, 205, 0, 0, 206, 207, + 0, 0, 332, 192, 193, 0, 333, 334, 78, 335, + 0, 0, 336, 0, 0, 0, 337, 194, 0, 0, + 0, 0, 0, 338, 339, 5, 340, 331, 341, 342, + 196, 343, 0, 0, 344, 0, 0, 0, 0, 0, + 80, 0, 0, 81, 20, 0, 0, 0, 0, 0, + 0, 345, 0, 157, 627, 0, 0, 346, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 0, 0, + 332, 192, 193, 0, 333, 334, 78, 335, 0, 0, + 336, 0, 0, 0, 337, 194, 0, 0, 0, 0, + 0, 338, 339, 5, 340, 331, 341, 342, 196, 343, + 0, 0, 344, 0, 0, 0, 0, 0, 80, 0, + 0, 81, 20, 0, 0, 0, 0, 0, 0, 345, + 0, 157, 675, 0, 0, 346, 0, 0, 202, 203, + 204, 205, 0, 0, 206, 207, 0, 0, 332, 192, + 193, 0, 333, 334, 78, 335, 0, 0, 336, 0, + 0, 0, 337, 194, 0, 0, 0, 0, 0, 338, + 339, 5, 340, 331, 341, 342, 196, 343, 0, 0, + 344, 0, 0, 0, 0, 0, 80, 0, 0, 81, + 20, 0, 0, 0, 0, 0, 0, 345, 0, 157, + 0, 0, 0, 346, 0, 0, 202, 203, 204, 205, + 0, 0, 206, 207, 0, 0, 529, 192, 193, 0, + 333, 334, 78, 335, 0, 0, 336, 0, 0, 0, + 337, 194, 0, 0, 0, 0, 0, 338, 339, 331, + 340, 0, 341, 342, 196, 343, 0, 0, 344, 0, + 0, 0, 0, 0, 80, 0, 0, 81, 20, 0, + 0, 0, 0, 0, 0, 345, 0, 157, 0, 0, + 0, 346, 0, 0, 202, 203, 204, 205, 0, 0, + 206, 207, 529, 192, 193, 0, 682, 334, 78, 335, + 0, 0, 336, 0, 0, 0, 337, 194, 0, 0, + 0, 0, 0, 338, 339, 0, 340, 0, 341, 342, + 196, 343, 0, 189, 344, 190, 191, 0, 0, 0, + 80, 0, 0, 81, 20, 0, 0, 0, 0, 0, + 0, 345, 0, 157, 0, 0, 0, 346, 0, 0, + 202, 203, 204, 205, 0, 0, 206, 207, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 192, 193, 0, + 0, 0, 78, 0, 489, 0, 190, 191, 0, 0, + 0, 194, 0, 0, 0, 0, 0, 195, 0, 0, + 0, 0, 0, 0, 196, 0, 0, 0, 197, 0, + 0, 0, 0, 0, 80, 0, 0, 81, 20, 0, + 0, 198, 199, 0, 0, 200, 0, 201, 192, 193, + 0, 0, 0, 78, 202, 203, 204, 205, 0, 0, + 206, 207, 194, 0, 0, 0, 0, 0, 195, 504, + 0, 190, 191, 0, 0, 196, 0, 0, 0, 197, + 0, 0, 0, 0, 0, 80, 0, 0, 81, 20, + 0, 490, 198, 199, 0, 0, 200, 0, 0, 0, + 0, 0, 0, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 192, 193, 0, 0, 0, 78, 0, + 556, 0, 190, 191, 0, 0, 0, 194, 0, 0, + 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, + 196, 0, 0, 0, 197, 0, 0, 0, 0, 0, + 80, 0, 0, 81, 20, 0, 0, 198, 199, 0, + 0, 200, 0, 0, 192, 193, 0, 505, 0, 78, + 202, 203, 204, 205, 0, 0, 206, 207, 194, 0, + 0, 0, 0, 0, 195, 565, 0, 190, 191, 0, + 0, 196, 0, 0, 0, 197, 0, 0, 0, 0, + 0, 80, 0, 0, 81, 20, 0, 0, 198, 199, + 0, 0, 200, 0, 0, 0, 0, 557, 0, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 192, + 193, 0, 0, 0, 78, 0, 436, 0, 190, 191, + 0, 0, 0, 194, 0, 0, 0, 0, 0, 195, + 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, + 197, 0, 0, 0, 0, 0, 80, 0, 0, 81, + 20, 0, 0, 198, 199, 0, 0, 200, 566, 0, + 192, 193, 0, 0, 0, 78, 202, 203, 204, 205, + 0, 0, 206, 207, 194, 0, 0, 0, 0, 0, + 195, 436, 0, 190, 191, 0, 0, 196, 0, 0, + 0, 197, 0, 0, 0, 0, 0, 80, 0, 0, + 81, 20, 0, 0, 198, 199, 0, 0, 200, 0, + 0, 0, 0, 557, 0, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 192, 193, 0, 0, 0, + 78, 0, 611, 0, 190, 191, 0, 0, 0, 194, + 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, + 0, 0, 196, 0, 0, 0, 197, 0, 0, 0, + 0, 0, 80, 0, 0, 81, 20, 0, 0, 198, + 199, 0, 0, 200, 0, 0, 192, 193, 148, 0, + 0, 78, 202, 203, 204, 205, 0, 0, 206, 207, + 194, 0, 0, 0, 0, 0, 195, 617, 0, 190, + 191, 0, 0, 196, 0, 0, 0, 197, 0, 0, + 0, 0, 0, 80, 0, 0, 81, 20, 0, 0, + 198, 199, 0, 0, 200, 612, 0, 0, 0, 0, + 0, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 192, 193, 0, 0, 0, 78, 0, 611, 0, + 190, 191, 0, 0, 0, 194, 0, 0, 0, 0, + 0, 195, 0, 0, 0, 0, 0, 0, 196, 0, + 0, 0, 197, 0, 0, 0, 0, 0, 80, 0, + 0, 81, 20, 0, 0, 198, 199, 0, 0, 200, + 0, 0, 192, 193, 0, 618, 0, 78, 202, 203, + 204, 205, 0, 0, 206, 207, 194, 0, 0, 0, + 0, 0, 195, 698, 0, 190, 191, 0, 0, 196, + 0, 0, 0, 197, 0, 0, 0, 0, 0, 80, + 0, 0, 81, 20, 0, 0, 198, 199, 0, 0, + 200, 676, 0, 0, 0, 0, 0, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 192, 193, 0, + 0, 0, 78, 0, 698, 0, 190, 191, 0, 0, + 0, 194, 0, 0, 0, 0, 0, 195, 0, 0, + 0, 0, 0, 0, 196, 0, 0, 0, 197, 0, + 0, 0, 0, 0, 80, 0, 0, 81, 20, 0, + 0, 198, 199, 0, 0, 200, 699, 0, 192, 193, + 0, 0, 0, 78, 202, 203, 204, 205, 0, 0, + 206, 207, 194, 0, 0, 0, 0, 0, 195, 617, + 0, 190, 191, 0, 0, 196, 0, 0, 0, 197, + 0, 0, 0, 0, 0, 80, 0, 0, 81, 20, + 0, 0, 198, 199, 0, 0, 200, 731, 0, 0, + 0, 0, 0, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 192, 193, 0, 0, 0, 78, 0, + 266, 0, 190, 191, 0, 0, 0, 194, 0, 0, + 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, + 196, 0, 0, 0, 197, 0, 0, 0, 0, 0, + 80, 0, 0, 81, 20, 0, 0, 198, 199, 0, + 0, 200, 0, 0, 192, 193, 0, 736, 0, 78, + 202, 203, 204, 205, 0, 0, 206, 207, 194, 0, + 0, 0, 0, 0, 195, 271, 0, 190, 191, 0, + 0, 196, 0, 0, 0, 197, 0, 0, 0, 0, + 0, 80, 0, 0, 81, 20, 0, 0, 198, 199, + 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 192, + 193, 0, 0, 0, 78, 0, 273, 0, 190, 191, + 0, 0, 0, 194, 0, 0, 0, 0, 0, 195, + 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, + 197, 0, 0, 0, 0, 0, 80, 0, 0, 81, + 20, 0, 0, 198, 199, 0, 0, 200, 0, 0, + 192, 193, 0, 0, 0, 78, 202, 203, 204, 205, + 0, 0, 206, 207, 194, 0, 0, 0, 0, 0, + 195, 275, 0, 190, 191, 0, 0, 196, 0, 0, + 0, 197, 0, 0, 0, 0, 0, 80, 0, 0, + 81, 20, 0, 0, 198, 199, 0, 0, 200, 0, + 0, 0, 0, 0, 0, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 192, 193, 0, 0, 0, + 78, 0, 284, 0, 190, 191, 0, 0, 0, 194, + 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, + 0, 0, 196, 0, 0, 0, 197, 0, 0, 0, + 0, 0, 80, 0, 0, 81, 20, 0, 0, 198, + 199, 0, 0, 200, 0, 0, 192, 193, 0, 0, + 0, 78, 202, 203, 204, 205, 0, 0, 206, 207, + 194, 0, 0, 0, 0, 0, 195, 286, 0, 190, + 191, 0, 0, 196, 0, 0, 0, 197, 0, 0, + 0, 0, 0, 80, 0, 0, 81, 20, 0, 0, + 198, 199, 0, 0, 200, 0, 0, 0, 0, 0, + 0, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 192, 193, 0, 0, 0, 78, 0, 288, 0, + 190, 191, 0, 0, 0, 194, 0, 0, 0, 0, + 0, 195, 0, 0, 0, 0, 0, 0, 196, 0, + 0, 0, 197, 0, 0, 0, 0, 0, 80, 0, + 0, 81, 20, 0, 0, 198, 199, 0, 0, 200, + 0, 0, 192, 193, 0, 0, 0, 78, 202, 203, + 204, 205, 0, 0, 206, 207, 194, 0, 0, 0, + 0, 0, 195, 436, 0, 190, 191, 0, 0, 196, + 0, 0, 0, 197, 0, 0, 0, 0, 0, 80, + 0, 0, 81, 20, 0, 0, 198, 199, 0, 0, + 200, 0, 0, 0, 0, 0, 0, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 192, 193, 0, + 0, 0, 78, 0, 444, 0, 190, 191, 0, 0, + 0, 194, 0, 0, 0, 0, 0, 195, 0, 0, + 0, 0, 0, 0, 196, 0, 0, 0, 197, 0, + 0, 0, 0, 0, 80, 0, 0, 81, 20, 0, + 0, 198, 199, 0, 0, 200, 0, 0, 192, 193, + 0, 0, 0, 78, 202, 203, 204, 205, 0, 0, + 206, 207, 194, 0, 0, 0, 0, 0, 195, 448, + 0, 190, 191, 0, 0, 196, 0, 0, 0, 197, + 0, 0, 0, 0, 0, 80, 0, 0, 81, 20, + 0, 0, 198, 199, 0, 0, 200, 0, 0, 0, + 0, 0, 0, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 192, 193, 0, 0, 0, 78, 0, + 450, 0, 190, 191, 0, 0, 0, 194, 0, 0, + 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, + 196, 0, 0, 0, 197, 0, 0, 0, 0, 0, + 80, 0, 0, 81, 20, 0, 0, 198, 199, 0, + 0, 200, 0, 0, 192, 193, 0, 0, 0, 78, + 202, 203, 204, 205, 0, 0, 206, 207, 194, 0, + 0, 0, 0, 0, 195, 452, 0, 190, 191, 0, + 0, 196, 0, 0, 0, 197, 0, 0, 0, 0, + 0, 80, 0, 0, 81, 20, 0, 0, 198, 199, + 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 192, + 193, 0, 0, 0, 78, 0, 454, 0, 190, 191, + 0, 0, 0, 194, 0, 0, 0, 0, 0, 195, + 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, + 197, 0, 0, 0, 0, 0, 80, 0, 0, 81, + 20, 0, 0, 198, 199, 0, 0, 200, 0, 0, + 192, 193, 0, 0, 0, 78, 202, 203, 204, 205, + 0, 0, 206, 207, 194, 0, 0, 0, 0, 0, + 195, 456, 0, 190, 191, 0, 0, 196, 0, 0, + 0, 197, 0, 0, 0, 0, 0, 80, 0, 0, + 81, 20, 0, 0, 198, 199, 0, 0, 200, 0, + 0, 0, 0, 0, 0, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 192, 193, 0, 0, 0, + 78, 0, 458, 0, 190, 191, 0, 0, 0, 194, + 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, + 0, 0, 196, 0, 0, 0, 197, 0, 0, 0, + 0, 0, 80, 0, 0, 81, 20, 0, 0, 198, + 199, 0, 0, 200, 0, 0, 192, 193, 0, 0, + 0, 78, 202, 203, 204, 205, 0, 0, 206, 207, + 194, 0, 0, 0, 0, 0, 195, 460, 0, 190, + 191, 0, 0, 196, 0, 0, 0, 197, 0, 0, + 0, 0, 0, 80, 0, 0, 81, 20, 0, 0, + 198, 199, 0, 0, 200, 0, 0, 0, 0, 0, + 0, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 192, 193, 0, 0, 0, 78, 0, 462, 0, + 190, 191, 0, 0, 0, 194, 0, 0, 0, 0, + 0, 195, 0, 0, 0, 0, 0, 0, 196, 0, + 0, 0, 197, 0, 0, 0, 0, 0, 80, 0, + 0, 81, 20, 0, 0, 198, 199, 0, 0, 200, + 0, 0, 192, 193, 0, 0, 0, 78, 202, 203, + 204, 205, 0, 0, 206, 207, 194, 0, 0, 0, + 0, 0, 195, 464, 0, 190, 191, 0, 0, 196, + 0, 0, 0, 197, 0, 0, 0, 0, 0, 80, + 0, 0, 81, 20, 0, 0, 198, 199, 0, 0, + 200, 0, 0, 0, 0, 0, 0, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 192, 193, 0, + 0, 0, 78, 0, 466, 0, 190, 191, 0, 0, + 0, 194, 0, 0, 0, 0, 0, 195, 0, 0, + 0, 0, 0, 0, 196, 0, 0, 0, 197, 0, + 0, 0, 0, 0, 80, 0, 0, 81, 20, 0, + 0, 198, 199, 0, 0, 200, 0, 0, 192, 193, + 0, 0, 0, 78, 202, 203, 204, 205, 0, 0, + 206, 207, 194, 0, 0, 0, 0, 0, 195, 468, + 0, 190, 191, 0, 0, 196, 0, 0, 0, 197, + 0, 0, 0, 0, 0, 80, 0, 0, 81, 20, + 0, 0, 198, 199, 0, 0, 200, 0, 0, 0, + 0, 0, 0, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 192, 193, 0, 0, 0, 78, 0, + 470, 0, 190, 191, 0, 0, 0, 194, 0, 0, + 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, + 196, 0, 0, 0, 197, 0, 0, 0, 0, 0, + 80, 0, 0, 81, 20, 0, 0, 198, 199, 0, + 0, 200, 0, 0, 192, 193, 0, 0, 0, 78, + 202, 203, 204, 205, 0, 0, 206, 207, 194, 0, + 0, 0, 0, 0, 195, 475, 0, 190, 191, 0, + 0, 196, 0, 0, 0, 197, 0, 0, 0, 0, + 0, 80, 0, 0, 81, 20, 0, 0, 198, 199, + 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 192, + 193, 0, 0, 0, 78, 0, 477, 0, 190, 191, + 0, 0, 0, 194, 0, 0, 0, 0, 0, 195, + 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, + 197, 0, 0, 0, 0, 0, 80, 0, 0, 81, + 20, 0, 0, 198, 199, 0, 0, 200, 0, 0, + 192, 193, 0, 0, 0, 78, 202, 203, 204, 205, + 0, 0, 206, 207, 194, 0, 0, 0, 0, 0, + 195, 479, 0, 190, 191, 0, 0, 196, 0, 0, + 0, 197, 0, 0, 0, 0, 0, 80, 0, 0, + 81, 20, 0, 0, 198, 199, 0, 0, 200, 0, + 0, 0, 0, 0, 0, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 192, 193, 0, 0, 0, + 78, 0, 481, 0, 190, 191, 0, 0, 0, 194, + 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, + 0, 0, 196, 0, 0, 0, 197, 0, 0, 0, + 0, 0, 80, 0, 0, 81, 20, 0, 0, 198, + 199, 0, 0, 200, 0, 0, 192, 193, 0, 0, + 0, 78, 202, 203, 204, 205, 0, 0, 206, 207, + 194, 0, 0, 0, 0, 0, 195, 483, 0, 190, + 191, 0, 0, 196, 0, 0, 0, 197, 0, 0, + 0, 0, 0, 80, 0, 0, 81, 20, 0, 0, + 198, 199, 0, 0, 200, 0, 0, 0, 0, 0, + 0, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 192, 193, 0, 0, 0, 78, 0, 485, 0, + 190, 191, 0, 0, 0, 194, 0, 0, 0, 0, + 0, 195, 0, 0, 0, 0, 0, 0, 196, 0, + 0, 0, 197, 0, 0, 0, 0, 0, 80, 0, + 0, 81, 20, 0, 0, 198, 199, 0, 0, 200, + 0, 0, 192, 193, 0, 0, 0, 78, 202, 203, + 204, 205, 0, 0, 206, 207, 194, 0, 0, 0, + 0, 0, 195, 487, 0, 190, 191, 0, 0, 196, + 0, 0, 0, 197, 0, 0, 0, 0, 0, 80, + 0, 0, 81, 20, 0, 0, 198, 199, 0, 0, + 200, 0, 0, 0, 0, 0, 0, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 192, 193, 0, + 0, 0, 78, 0, 492, 0, 190, 191, 0, 0, + 0, 194, 0, 0, 0, 0, 0, 195, 0, 0, + 0, 0, 0, 0, 196, 0, 0, 0, 197, 0, + 0, 0, 0, 0, 80, 0, 0, 81, 20, 0, + 0, 198, 199, 0, 0, 200, 0, 0, 192, 193, + 0, 0, 0, 78, 202, 203, 204, 205, 0, 0, + 206, 207, 194, 0, 0, 0, 0, 0, 195, 499, + 0, 190, 191, 0, 0, 196, 0, 0, 0, 197, + 0, 0, 0, 0, 0, 80, 0, 0, 81, 20, + 0, 0, 198, 199, 0, 0, 200, 0, 0, 0, + 0, 0, 0, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, 192, 193, 0, 0, 0, 78, 0, + 568, 0, 190, 191, 0, 0, 0, 194, 0, 0, + 0, 0, 0, 195, 0, 0, 0, 0, 0, 0, + 196, 0, 0, 0, 197, 0, 0, 0, 0, 0, + 80, 0, 0, 81, 20, 0, 0, 198, 199, 0, + 0, 200, 0, 0, 192, 193, 0, 0, 0, 78, + 202, 203, 204, 205, 0, 0, 206, 207, 194, 0, + 0, 0, 0, 0, 195, 588, 0, 190, 191, 0, + 0, 196, 0, 0, 0, 197, 0, 0, 0, 0, + 0, 80, 0, 0, 81, 20, 0, 0, 198, 199, + 0, 0, 200, 0, 0, 0, 0, 0, 0, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 192, + 193, 0, 0, 0, 78, 0, 596, 0, 190, 191, + 0, 0, 0, 194, 0, 0, 0, 0, 0, 195, + 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, + 197, 0, 0, 0, 0, 0, 80, 0, 0, 81, + 20, 0, 0, 198, 199, 0, 0, 200, 0, 0, + 192, 193, 0, 0, 0, 78, 202, 203, 204, 205, + 0, 0, 206, 207, 194, 0, 0, 0, 0, 0, + 195, 598, 0, 190, 191, 0, 0, 196, 0, 0, + 0, 197, 0, 0, 0, 0, 0, 80, 0, 0, + 81, 20, 0, 0, 198, 199, 0, 0, 200, 0, + 0, 0, 0, 0, 0, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 192, 193, 0, 0, 0, + 78, 0, 620, 0, 190, 191, 0, 0, 0, 194, + 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, + 0, 0, 196, 0, 0, 0, 197, 0, 0, 0, + 0, 0, 80, 0, 0, 81, 20, 0, 0, 198, + 199, 0, 0, 200, 0, 0, 192, 193, 0, 0, + 0, 78, 202, 203, 204, 205, 0, 0, 206, 207, + 194, 0, 0, 0, 0, 0, 195, 637, 0, 190, + 191, 0, 0, 196, 0, 0, 0, 197, 0, 0, + 0, 0, 0, 80, 0, 0, 81, 20, 0, 0, + 198, 199, 0, 0, 200, 0, 0, 0, 0, 0, + 0, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207, 192, 193, 0, 0, 0, 78, 0, 641, 0, + 190, 191, 0, 0, 0, 194, 0, 0, 0, 0, + 0, 195, 0, 0, 0, 0, 0, 0, 196, 0, + 0, 0, 197, 0, 0, 0, 0, 0, 80, 0, + 0, 81, 20, 0, 0, 198, 199, 0, 0, 200, + 0, 0, 192, 193, 0, 0, 0, 78, 202, 203, + 204, 205, 0, 0, 206, 207, 194, 0, 0, 0, + 0, 0, 195, 647, 0, 190, 191, 0, 0, 196, + 0, 0, 0, 197, 0, 0, 0, 0, 0, 80, + 0, 0, 81, 20, 0, 0, 198, 199, 0, 0, + 200, 0, 0, 0, 0, 0, 0, 0, 0, 202, + 203, 204, 205, 0, 0, 206, 207, 192, 193, 0, + 0, 0, 78, 0, 740, 0, 190, 191, 0, 0, + 0, 194, 0, 0, 0, 0, 0, 195, 0, 0, + 0, 0, 0, 0, 196, 0, 0, 0, 197, 0, + 0, 0, 0, 0, 80, 0, 0, 81, 20, 0, + 0, 198, 199, 0, 0, 200, 0, 0, 192, 193, + 0, 0, 0, 78, 202, 203, 204, 205, 0, 0, + 206, 207, 194, 0, 0, 0, 0, 0, 195, 0, + 605, 0, 0, 0, 0, 196, 0, 0, 0, 197, + 0, 0, 0, 0, 0, 80, 0, 0, 81, 20, + 0, 0, 198, 199, 0, 668, 200, 0, 0, 0, + 0, 0, 0, 0, 0, 202, 203, 204, 205, 0, + 0, 206, 207, -284, -284, -284, 0, 0, 0, -284, + 0, 0, 0, 0, 0, 0, 0, 0, -284, 0, + 0, 0, 0, 0, -284, 0, 0, 704, 0, 192, + 193, -284, 0, 0, 78, -284, 0, 0, 0, 0, + 0, -284, 0, 194, -284, -284, 0, 0, 0, 195, + 0, 0, -284, 0, 190, 191, 196, 0, -284, 0, + 197, -284, -284, -284, -284, 0, 80, -284, -284, 81, + 20, 192, 193, 0, 0, 0, 78, 345, -292, 0, + 0, 0, 0, 0, 0, 194, 202, 203, 204, 205, + 0, 195, 206, 207, 666, 0, 192, 193, 196, 0, + 0, 78, 197, 0, 0, 0, 0, 0, 80, 0, + 194, 81, 20, 0, 0, 0, 195, 0, 0, 345, + -292, 190, 191, 196, 0, 0, 0, 197, 202, 203, + 204, 205, 0, 80, 206, 207, 81, 20, 192, 193, + 198, 199, 0, 78, 200, 0, 201, 292, 0, 0, + 0, 293, 194, 202, 203, 204, 205, 0, 195, 206, + 207, 0, 0, 192, 193, 196, 0, 0, 78, 197, + 0, 0, 190, 191, 0, 80, 0, 194, 81, 20, + 0, 0, 0, 195, 0, 0, 345, 0, 0, 0, + 196, 0, 0, 0, 197, 202, 203, 204, 205, 0, + 80, 206, 207, 81, 20, 0, 0, 198, 199, 0, + 0, 200, 433, 0, 192, 193, 0, 0, 0, 78, + 202, 203, 204, 205, 0, 0, 206, 207, 194, 0, + 0, 0, 0, 0, 195, 0, 0, 190, 191, 0, + 0, 196, 0, 0, 0, 197, 0, 0, 0, 0, + 0, 80, 0, 0, 81, 20, 0, 0, 198, 199, + 0, 0, 200, 584, 0, 0, 0, 0, 0, 0, + 0, 202, 203, 204, 205, 0, 0, 206, 207, 192, + 193, 0, 0, 0, 78, 0, 0, 0, 190, 191, + 0, 0, 0, 194, 0, 0, 0, 0, 0, 195, + 0, 0, 0, 0, 0, 0, 196, 0, 0, 0, + 197, 0, 0, 0, 0, 0, 80, 0, 0, 81, + 20, 0, 0, 198, 199, 0, 0, 200, 628, 0, + 192, 193, 0, 0, 0, 78, 202, 203, 204, 205, + 0, 0, 206, 207, 194, 0, 0, 0, 0, 0, + 195, 0, 0, 190, 191, 0, 0, 196, 0, 0, + 0, 197, 0, 0, 0, 0, 0, 80, 0, 0, + 81, 20, 0, 0, 198, 199, 0, 0, 200, 643, + 0, 0, 0, 0, 0, 0, 0, 202, 203, 204, + 205, 0, 0, 206, 207, 192, 193, 0, 0, 0, + 78, 0, 0, 0, 0, 0, 0, 0, 0, 194, + 0, 0, 0, 0, 0, 195, 0, 0, 0, 0, + 0, 0, 196, 0, 0, 0, 197, 0, 0, 0, + 0, 0, 80, 0, 0, 81, 20, 0, 0, 198, + 199, 0, 0, 200, 0, 2, 192, 193, 0, 0, + 0, 78, 202, 203, 204, 205, 0, 0, 206, 207, + 194, 0, 0, 0, 0, 0, 195, 0, 0, 0, + 0, 0, 0, 196, 0, 0, 0, 197, 0, 0, + 0, 0, 0, 80, 0, 0, 81, 20, 0, 0, + 0, 0, 0, 0, 345, 0, 0, 0, 0, 0, + 0, 0, 0, 202, 203, 204, 205, 0, 0, 206, + 207 +}; + +static const short yycheck[] = { 3, + 132, 123, 6, 62, 264, 201, 0, 427, 129, 1, + 1, 1, 282, 1, 355, 9, 10, 11, 1, 289, + 290, 1, 0, 99, 100, 1, 1, 62, 1, 251, + 89, 9, 10, 11, 134, 94, 30, 374, 42, 33, + 34, 162, 46, 117, 86, 42, 1, 1, 169, 46, + 420, 53, 30, 100, 721, 33, 34, 51, 62, 94, + 64, 1, 362, 94, 101, 69, 97, 64, 62, 369, + 129, 371, 69, 51, 133, 62, 150, 447, 745, 153, + 63, 95, 4, 5, 62, 89, 1, 1, 140, 97, + 94, 67, 1, 101, 129, 97, 196, 171, 97, 1, + 94, 160, 89, 162, 1, 93, 98, 94, 99, 99, + 101, 101, 95, 101, 36, 37, 94, 1, 40, 178, + 95, 101, 1, 650, 128, 129, 99, 162, 50, 133, + 134, 128, 1, 52, 1, 129, 257, 134, 1, 133, + 95, 95, 129, 1, 414, 99, 133, 417, 200, 201, + 1, 129, 572, 1, 94, 525, 160, 79, 162, 686, + 100, 83, 689, 0, 1, 265, 1, 1, 162, 190, + 191, 192, 193, 160, 178, 162, 398, 198, 199, 253, + 1, 95, 1, 98, 162, 555, 190, 191, 192, 193, + 99, 178, 196, 252, 198, 199, 200, 99, 100, 196, + 122, 123, 99, 100, 1, 264, 1, 44, 1, 196, + 551, 581, 1, 200, 98, 94, 94, 139, 55, 251, + 341, 100, 95, 101, 61, 347, 99, 94, 755, 98, + 67, 94, 1, 100, 430, 1, 763, 100, 765, 1, + 767, 99, 1, 94, 1, 1, 298, 251, 252, 100, + 302, 99, 1, 1, 88, 177, 626, 1, 252, 1, + 264, 265, 99, 98, 251, 252, 97, 86, 265, 1, + 264, 100, 15, 1, 9, 327, 1, 264, 99, 616, + 99, 618, 334, 52, 625, 337, 307, 308, 309, 86, + 1, 661, 351, 345, 216, 1, 95, 1, 33, 88, + 95, 94, 99, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, 322, 323, + 324, 325, 326, 355, 650, 1, 95, 549, 1, 251, + 362, 1, 319, 99, 671, 94, 98, 369, 708, 371, + 262, 98, 374, 99, 87, 94, 94, 351, 52, 650, + 650, 355, 0, 1, 93, 99, 98, 279, 362, 63, + 686, 413, 94, 689, 351, 369, 398, 371, 355, 650, + 374, 99, 424, 671, 99, 98, 1, 299, 430, 301, + 374, 1, 93, 251, 1, 686, 686, 374, 689, 689, + 63, 95, 98, 1, 398, 655, 44, 67, 1, 736, + 421, 94, 524, 703, 97, 686, 747, 55, 689, 129, + 86, 398, 712, 61, 336, 1, 1, 421, 1, 67, + 757, 343, 95, 427, 1, 347, 1, 75, 1, 755, + 730, 95, 52, 355, 566, 0, 1, 763, 736, 765, + 362, 767, 162, 63, 0, 1, 498, 369, 1, 371, + 1, 99, 584, 96, 755, 755, 508, 100, 510, 757, + 1, 86, 763, 763, 765, 765, 767, 767, 520, 1, + 1, 1, 96, 1, 755, 95, 398, 536, 1, 44, + 601, 1, 763, 86, 765, 93, 767, 355, 44, 541, + 55, 543, 45, 46, 362, 1, 61, 1, 72, 55, + 95, 369, 67, 371, 636, 61, 374, 93, 93, 93, + 93, 67, 86, 86, 646, 92, 93, 549, 93, 551, + 97, 98, 99, 100, 53, 1, 578, 0, 1, 251, + 398, 1, 536, 86, 99, 88, 129, 44, 91, 92, + 93, 100, 93, 99, 97, 549, 50, 551, 101, 536, + 571, 92, 673, 94, 61, 86, 97, 98, 99, 100, + 67, 93, 549, 93, 551, 93, 101, 571, 572, 162, + 93, 44, 65, 93, 50, 0, 1, 1, 82, 72, + 86, 85, 86, 587, 616, 1, 618, 95, 61, 97, + 1, 83, 1, 625, 67, 92, 655, 0, 1, 521, + 97, 98, 524, 724, 95, 96, 82, 177, 99, 85, + 86, 0, 1, 665, 107, 1, 86, 1, 650, 44, + 1, 625, 1, 5, 6, 7, 99, 549, 44, 551, + 122, 123, 414, 355, 50, 417, 61, 1, 625, 671, + 362, 44, 67, 101, 94, 1, 650, 369, 101, 371, + 100, 655, 374, 1, 686, 44, 97, 689, 61, 711, + 1, 655, 86, 715, 67, 717, 82, 1, 655, 85, + 86, 703, 61, 251, 99, 86, 398, 86, 67, 11, + 712, 549, 686, 551, 65, 689, 67, 12, 67, 721, + 1, 72, 262, 72, 5, 76, 99, 76, 730, 703, + 86, 623, 86, 625, 736, 86, 13, 86, 712, 65, + 99, 67, 1, 745, 97, 747, 72, 721, 101, 1, + 76, 1, 86, 755, 1, 757, 730, 14, 650, 1, + 86, 763, 99, 765, 721, 767, 251, 64, 86, 97, + 60, 745, 69, 747, 64, 86, 45, 46, 616, 96, + 618, 755, 86, 99, 100, 45, 46, 625, 745, 763, + 747, 765, 95, 767, 686, 93, 1, 689, 9, 97, + 11, 93, 44, 101, 44, 86, 93, 355, 50, 47, + 50, 703, 650, 99, 362, 47, 686, 99, 1, 689, + 712, 369, 33, 371, 62, 99, 374, 86, 97, 721, + 62, 128, 101, 671, 86, 129, 86, 97, 730, 86, + 82, 101, 82, 85, 86, 85, 86, 1, 686, 251, + 398, 689, 94, 745, 94, 747, 99, 549, 96, 551, + 99, 44, 93, 755, 96, 703, 160, 50, 162, 94, + 355, 763, 97, 765, 712, 767, 101, 362, 315, 316, + 317, 318, 94, 721, 369, 755, 371, 251, 100, 374, + 91, 92, 730, 763, 93, 765, 50, 767, 736, 82, + 44, 88, 85, 86, 94, 59, 50, 745, 94, 747, + 100, 65, 100, 398, 100, 94, 66, 755, 72, 757, + 10, 100, 76, 67, 616, 763, 618, 765, 82, 767, + 99, 85, 86, 625, 93, 89, 90, 94, 82, 93, + 30, 85, 86, 100, 34, 416, 1, 418, 102, 103, + 104, 105, 97, 355, 108, 109, 91, 92, 650, 86, + 362, 51, 45, 46, 91, 92, 93, 369, 94, 371, + 97, 1, 374, 93, 101, 251, 44, 3, 4, 671, + 16, 17, 50, 99, 18, 19, 20, 21, 94, 44, + 94, 355, 91, 92, 686, 50, 398, 689, 362, 97, + 98, 549, 1, 551, 59, 369, 61, 371, 94, 44, + 374, 703, 67, 100, 82, 50, 56, 85, 86, 56, + 712, 45, 46, 57, 59, 99, 61, 82, 94, 721, + 85, 86, 67, 94, 398, 91, 92, 93, 730, 45, + 46, 97, 310, 311, 736, 101, 1, 82, 320, 321, + 85, 86, 94, 745, 1, 747, 8, 9, 10, 56, + 95, 96, 94, 755, 549, 757, 551, 0, 616, 94, + 618, 763, 99, 765, 44, 767, 99, 625, 94, 355, + 50, 0, 91, 92, 93, 319, 362, 11, 97, 59, + 54, 61, 101, 369, 44, 371, 139, 67, 374, 86, + 50, 75, 650, 162, 91, 92, 93, 160, 393, 59, + 97, 61, 82, 252, 101, 85, 86, 67, 97, 98, + 99, 52, 398, 671, 282, 95, 96, 398, 44, 94, + 374, 616, 82, 618, 50, 85, 86, 719, 686, 719, + 625, 689, 602, 59, 374, 61, 96, 549, 602, 551, + 322, 67, 86, 323, 325, 703, 324, 91, 92, 93, + 312, 313, 314, 97, 712, 650, 82, 101, 587, 85, + 86, 326, -1, 721, 330, -1, -1, -1, -1, -1, + 96, -1, 730, -1, -1, 549, 671, 551, 736, -1, + 91, 92, 93, -1, -1, -1, 97, 745, -1, 747, + 101, 686, -1, -1, 689, -1, -1, 755, -1, 757, + -1, -1, -1, -1, 616, 763, 618, 765, 703, 767, + -1, -1, -1, 625, -1, -1, -1, 712, -1, -1, + -1, -1, -1, -1, -1, -1, 721, -1, -1, -1, + -1, -1, -1, -1, -1, 730, -1, -1, 650, -1, + -1, 736, 616, -1, 618, -1, -1, -1, -1, 50, + 745, 625, 747, -1, -1, -1, -1, -1, 59, 671, + 755, -1, 757, 549, 65, 551, -1, -1, 763, -1, + 765, 72, 767, -1, 686, 76, 650, 689, -1, -1, + -1, 82, -1, -1, 85, 86, -1, -1, 89, 90, + -1, 703, 93, -1, -1, -1, -1, 671, -1, -1, + 712, 102, 103, 104, 105, -1, -1, 108, 109, 721, + -1, -1, 686, -1, -1, 689, -1, -1, 730, -1, + -1, -1, -1, -1, 736, -1, -1, -1, -1, 703, + 616, -1, 618, 745, -1, 747, -1, -1, 712, 625, + -1, -1, -1, 755, -1, 757, -1, 721, -1, -1, + -1, 763, -1, 765, -1, 767, 730, -1, -1, -1, + -1, -1, 736, -1, 650, -1, 190, 191, 192, 193, + -1, 745, -1, 747, 198, 199, -1, -1, -1, -1, + -1, 755, -1, 757, -1, 671, -1, -1, -1, 763, + -1, 765, -1, 767, -1, -1, 190, 191, 192, 193, + 686, -1, -1, 689, 198, 199, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 703, -1, -1, + -1, -1, -1, -1, -1, -1, 712, -1, -1, -1, + -1, -1, -1, -1, -1, 721, -1, -1, -1, -1, + -1, -1, -1, -1, 730, -1, -1, -1, -1, -1, + 736, -1, -1, -1, -1, -1, -1, -1, -1, 745, + -1, 747, -1, -1, -1, -1, -1, -1, -1, 755, + -1, 757, -1, -1, -1, -1, -1, 763, -1, 765, + -1, 767, -1, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, -1, 320, 321, 322, 323, + 324, 325, 326, -1, 1, -1, -1, -1, -1, -1, + -1, -1, -1, 307, 308, 309, 310, 311, 312, 313, + 314, 315, 316, 317, 318, -1, 320, 321, 322, 323, + 324, 325, 326, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 44, 45, 46, + 47, 48, 49, 50, 51, -1, -1, 54, -1, -1, + -1, 58, 59, -1, -1, 62, -1, -1, 65, 66, + 67, 68, -1, 70, 71, 72, 73, -1, -1, 76, + -1, -1, -1, -1, -1, 82, -1, -1, 85, 86, + -1, 1, -1, -1, -1, -1, 93, 421, 95, 96, + -1, -1, 99, 427, -1, 102, 103, 104, 105, -1, + -1, 108, 109, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 421, -1, -1, + -1, -1, -1, 427, 44, 45, 46, 47, 48, 49, + 50, 51, -1, -1, 54, -1, -1, -1, 58, 59, + -1, -1, 62, -1, -1, 65, 66, 67, 68, -1, + 70, 71, 72, 73, -1, 1, 76, 3, 4, -1, + -1, -1, 82, -1, -1, 85, 86, -1, -1, -1, + -1, -1, -1, 93, -1, 95, 96, -1, -1, 99, + -1, -1, 102, 103, 104, 105, -1, -1, 108, 109, + -1, -1, -1, -1, -1, -1, -1, -1, -1, 45, + 46, -1, -1, -1, 50, -1, -1, -1, -1, -1, + -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, 72, 1, -1, -1, + 76, -1, -1, -1, -1, -1, 82, 571, 572, 85, + 86, -1, -1, 89, 90, -1, -1, 93, -1, 95, + 96, -1, -1, 587, -1, -1, 102, 103, 104, 105, + -1, -1, 108, 109, -1, -1, -1, 571, 572, -1, + 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, + 54, -1, -1, 587, 58, 59, -1, -1, 62, -1, + -1, 65, 66, 67, 68, 1, 70, 71, 72, 73, + -1, -1, 76, -1, -1, -1, -1, -1, 82, -1, + -1, 85, 86, -1, -1, -1, -1, -1, -1, 93, + -1, 95, 96, -1, -1, 99, -1, -1, 102, 103, + 104, 105, -1, -1, 108, 109, -1, -1, 44, 45, + 46, -1, 48, 49, 50, 51, -1, -1, 54, -1, + -1, -1, 58, 59, -1, -1, -1, -1, -1, 65, + 66, 67, 68, 1, 70, 71, 72, 73, -1, -1, + 76, -1, -1, -1, -1, -1, 82, -1, -1, 85, + 86, -1, -1, -1, -1, -1, -1, 93, -1, 95, + 96, -1, -1, 99, -1, -1, 102, 103, 104, 105, + -1, -1, 108, 109, -1, -1, 44, 45, 46, -1, + 48, 49, 50, 51, -1, -1, 54, -1, -1, -1, + 58, 59, -1, -1, -1, -1, -1, 65, 66, 67, + 68, 1, 70, 71, 72, 73, -1, -1, 76, -1, + -1, -1, -1, -1, 82, -1, -1, 85, 86, -1, + -1, -1, -1, -1, -1, 93, -1, 95, 96, -1, + -1, 99, -1, -1, 102, 103, 104, 105, -1, -1, + 108, 109, -1, -1, 44, 45, 46, -1, 48, 49, + 50, 51, -1, -1, 54, -1, -1, -1, 58, 59, + -1, -1, -1, -1, -1, 65, 66, 67, 68, 1, + 70, 71, 72, 73, -1, -1, 76, -1, -1, -1, + -1, -1, 82, -1, -1, 85, 86, -1, -1, -1, + -1, -1, -1, 93, -1, 95, 96, -1, -1, 99, + -1, -1, 102, 103, 104, 105, -1, -1, 108, 109, + -1, -1, 44, 45, 46, -1, 48, 49, 50, 51, + -1, -1, 54, -1, -1, -1, 58, 59, -1, -1, + -1, -1, -1, 65, 66, 67, 68, 1, 70, 71, + 72, 73, -1, -1, 76, -1, -1, -1, -1, -1, + 82, -1, -1, 85, 86, -1, -1, -1, -1, -1, + -1, 93, -1, 95, 96, -1, -1, 99, -1, -1, + 102, 103, 104, 105, -1, -1, 108, 109, -1, -1, + 44, 45, 46, -1, 48, 49, 50, 51, -1, -1, + 54, -1, -1, -1, 58, 59, -1, -1, -1, -1, + -1, 65, 66, 67, 68, 1, 70, 71, 72, 73, + -1, -1, 76, -1, -1, -1, -1, -1, 82, -1, + -1, 85, 86, -1, -1, -1, -1, -1, -1, 93, + -1, 95, 96, -1, -1, 99, -1, -1, 102, 103, + 104, 105, -1, -1, 108, 109, -1, -1, 44, 45, + 46, -1, 48, 49, 50, 51, -1, -1, 54, -1, + -1, -1, 58, 59, -1, -1, -1, -1, -1, 65, + 66, 67, 68, 1, 70, 71, 72, 73, -1, -1, + 76, -1, -1, -1, -1, -1, 82, -1, -1, 85, + 86, -1, -1, -1, -1, -1, -1, 93, -1, 95, + -1, -1, -1, 99, -1, -1, 102, 103, 104, 105, + -1, -1, 108, 109, -1, -1, 44, 45, 46, -1, + 48, 49, 50, 51, -1, -1, 54, -1, -1, -1, + 58, 59, -1, -1, -1, -1, -1, 65, 66, 1, + 68, -1, 70, 71, 72, 73, -1, -1, 76, -1, + -1, -1, -1, -1, 82, -1, -1, 85, 86, -1, + -1, -1, -1, -1, -1, 93, -1, 95, -1, -1, + -1, 99, -1, -1, 102, 103, 104, 105, -1, -1, + 108, 109, 44, 45, 46, -1, 48, 49, 50, 51, + -1, -1, 54, -1, -1, -1, 58, 59, -1, -1, + -1, -1, -1, 65, 66, -1, 68, -1, 70, 71, + 72, 73, -1, 1, 76, 3, 4, -1, -1, -1, + 82, -1, -1, 85, 86, -1, -1, -1, -1, -1, + -1, 93, -1, 95, -1, -1, -1, 99, -1, -1, + 102, 103, 104, 105, -1, -1, 108, 109, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 45, 46, -1, + -1, -1, 50, -1, 1, -1, 3, 4, -1, -1, + -1, 59, -1, -1, -1, -1, -1, 65, -1, -1, + -1, -1, -1, -1, 72, -1, -1, -1, 76, -1, + -1, -1, -1, -1, 82, -1, -1, 85, 86, -1, + -1, 89, 90, -1, -1, 93, -1, 95, 45, 46, + -1, -1, -1, 50, 102, 103, 104, 105, -1, -1, + 108, 109, 59, -1, -1, -1, -1, -1, 65, 1, + -1, 3, 4, -1, -1, 72, -1, -1, -1, 76, + -1, -1, -1, -1, -1, 82, -1, -1, 85, 86, + -1, 88, 89, 90, -1, -1, 93, -1, -1, -1, + -1, -1, -1, -1, -1, 102, 103, 104, 105, -1, + -1, 108, 109, 45, 46, -1, -1, -1, 50, -1, + 1, -1, 3, 4, -1, -1, -1, 59, -1, -1, + -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, + 72, -1, -1, -1, 76, -1, -1, -1, -1, -1, + 82, -1, -1, 85, 86, -1, -1, 89, 90, -1, + -1, 93, -1, -1, 45, 46, -1, 99, -1, 50, + 102, 103, 104, 105, -1, -1, 108, 109, 59, -1, + -1, -1, -1, -1, 65, 1, -1, 3, 4, -1, + -1, 72, -1, -1, -1, 76, -1, -1, -1, -1, + -1, 82, -1, -1, 85, 86, -1, -1, 89, 90, + -1, -1, 93, -1, -1, -1, -1, 98, -1, -1, + -1, 102, 103, 104, 105, -1, -1, 108, 109, 45, + 46, -1, -1, -1, 50, -1, 1, -1, 3, 4, + -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, + 76, -1, -1, -1, -1, -1, 82, -1, -1, 85, + 86, -1, -1, 89, 90, -1, -1, 93, 94, -1, + 45, 46, -1, -1, -1, 50, 102, 103, 104, 105, + -1, -1, 108, 109, 59, -1, -1, -1, -1, -1, + 65, 1, -1, 3, 4, -1, -1, 72, -1, -1, + -1, 76, -1, -1, -1, -1, -1, 82, -1, -1, + 85, 86, -1, -1, 89, 90, -1, -1, 93, -1, + -1, -1, -1, 98, -1, -1, -1, 102, 103, 104, + 105, -1, -1, 108, 109, 45, 46, -1, -1, -1, + 50, -1, 1, -1, 3, 4, -1, -1, -1, 59, + -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, + -1, -1, 72, -1, -1, -1, 76, -1, -1, -1, + -1, -1, 82, -1, -1, 85, 86, -1, -1, 89, + 90, -1, -1, 93, -1, -1, 45, 46, 98, -1, + -1, 50, 102, 103, 104, 105, -1, -1, 108, 109, + 59, -1, -1, -1, -1, -1, 65, 1, -1, 3, + 4, -1, -1, 72, -1, -1, -1, 76, -1, -1, + -1, -1, -1, 82, -1, -1, 85, 86, -1, -1, + 89, 90, -1, -1, 93, 94, -1, -1, -1, -1, + -1, -1, -1, 102, 103, 104, 105, -1, -1, 108, + 109, 45, 46, -1, -1, -1, 50, -1, 1, -1, + 3, 4, -1, -1, -1, 59, -1, -1, -1, -1, + -1, 65, -1, -1, -1, -1, -1, -1, 72, -1, + -1, -1, 76, -1, -1, -1, -1, -1, 82, -1, + -1, 85, 86, -1, -1, 89, 90, -1, -1, 93, + -1, -1, 45, 46, -1, 99, -1, 50, 102, 103, + 104, 105, -1, -1, 108, 109, 59, -1, -1, -1, + -1, -1, 65, 1, -1, 3, 4, -1, -1, 72, + -1, -1, -1, 76, -1, -1, -1, -1, -1, 82, + -1, -1, 85, 86, -1, -1, 89, 90, -1, -1, + 93, 94, -1, -1, -1, -1, -1, -1, -1, 102, + 103, 104, 105, -1, -1, 108, 109, 45, 46, -1, + -1, -1, 50, -1, 1, -1, 3, 4, -1, -1, + -1, 59, -1, -1, -1, -1, -1, 65, -1, -1, + -1, -1, -1, -1, 72, -1, -1, -1, 76, -1, + -1, -1, -1, -1, 82, -1, -1, 85, 86, -1, + -1, 89, 90, -1, -1, 93, 94, -1, 45, 46, + -1, -1, -1, 50, 102, 103, 104, 105, -1, -1, + 108, 109, 59, -1, -1, -1, -1, -1, 65, 1, + -1, 3, 4, -1, -1, 72, -1, -1, -1, 76, + -1, -1, -1, -1, -1, 82, -1, -1, 85, 86, + -1, -1, 89, 90, -1, -1, 93, 94, -1, -1, + -1, -1, -1, -1, -1, 102, 103, 104, 105, -1, + -1, 108, 109, 45, 46, -1, -1, -1, 50, -1, + 1, -1, 3, 4, -1, -1, -1, 59, -1, -1, + -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, + 72, -1, -1, -1, 76, -1, -1, -1, -1, -1, + 82, -1, -1, 85, 86, -1, -1, 89, 90, -1, + -1, 93, -1, -1, 45, 46, -1, 99, -1, 50, + 102, 103, 104, 105, -1, -1, 108, 109, 59, -1, + -1, -1, -1, -1, 65, 1, -1, 3, 4, -1, + -1, 72, -1, -1, -1, 76, -1, -1, -1, -1, + -1, 82, -1, -1, 85, 86, -1, -1, 89, 90, + -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, + -1, 102, 103, 104, 105, -1, -1, 108, 109, 45, + 46, -1, -1, -1, 50, -1, 1, -1, 3, 4, + -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, + 76, -1, -1, -1, -1, -1, 82, -1, -1, 85, + 86, -1, -1, 89, 90, -1, -1, 93, -1, -1, + 45, 46, -1, -1, -1, 50, 102, 103, 104, 105, + -1, -1, 108, 109, 59, -1, -1, -1, -1, -1, + 65, 1, -1, 3, 4, -1, -1, 72, -1, -1, + -1, 76, -1, -1, -1, -1, -1, 82, -1, -1, + 85, 86, -1, -1, 89, 90, -1, -1, 93, -1, + -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, + 105, -1, -1, 108, 109, 45, 46, -1, -1, -1, + 50, -1, 1, -1, 3, 4, -1, -1, -1, 59, + -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, + -1, -1, 72, -1, -1, -1, 76, -1, -1, -1, + -1, -1, 82, -1, -1, 85, 86, -1, -1, 89, + 90, -1, -1, 93, -1, -1, 45, 46, -1, -1, + -1, 50, 102, 103, 104, 105, -1, -1, 108, 109, + 59, -1, -1, -1, -1, -1, 65, 1, -1, 3, + 4, -1, -1, 72, -1, -1, -1, 76, -1, -1, + -1, -1, -1, 82, -1, -1, 85, 86, -1, -1, + 89, 90, -1, -1, 93, -1, -1, -1, -1, -1, + -1, -1, -1, 102, 103, 104, 105, -1, -1, 108, + 109, 45, 46, -1, -1, -1, 50, -1, 1, -1, + 3, 4, -1, -1, -1, 59, -1, -1, -1, -1, + -1, 65, -1, -1, -1, -1, -1, -1, 72, -1, + -1, -1, 76, -1, -1, -1, -1, -1, 82, -1, + -1, 85, 86, -1, -1, 89, 90, -1, -1, 93, + -1, -1, 45, 46, -1, -1, -1, 50, 102, 103, + 104, 105, -1, -1, 108, 109, 59, -1, -1, -1, + -1, -1, 65, 1, -1, 3, 4, -1, -1, 72, + -1, -1, -1, 76, -1, -1, -1, -1, -1, 82, + -1, -1, 85, 86, -1, -1, 89, 90, -1, -1, + 93, -1, -1, -1, -1, -1, -1, -1, -1, 102, + 103, 104, 105, -1, -1, 108, 109, 45, 46, -1, + -1, -1, 50, -1, 1, -1, 3, 4, -1, -1, + -1, 59, -1, -1, -1, -1, -1, 65, -1, -1, + -1, -1, -1, -1, 72, -1, -1, -1, 76, -1, + -1, -1, -1, -1, 82, -1, -1, 85, 86, -1, + -1, 89, 90, -1, -1, 93, -1, -1, 45, 46, + -1, -1, -1, 50, 102, 103, 104, 105, -1, -1, + 108, 109, 59, -1, -1, -1, -1, -1, 65, 1, + -1, 3, 4, -1, -1, 72, -1, -1, -1, 76, + -1, -1, -1, -1, -1, 82, -1, -1, 85, 86, + -1, -1, 89, 90, -1, -1, 93, -1, -1, -1, + -1, -1, -1, -1, -1, 102, 103, 104, 105, -1, + -1, 108, 109, 45, 46, -1, -1, -1, 50, -1, + 1, -1, 3, 4, -1, -1, -1, 59, -1, -1, + -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, + 72, -1, -1, -1, 76, -1, -1, -1, -1, -1, + 82, -1, -1, 85, 86, -1, -1, 89, 90, -1, + -1, 93, -1, -1, 45, 46, -1, -1, -1, 50, + 102, 103, 104, 105, -1, -1, 108, 109, 59, -1, + -1, -1, -1, -1, 65, 1, -1, 3, 4, -1, + -1, 72, -1, -1, -1, 76, -1, -1, -1, -1, + -1, 82, -1, -1, 85, 86, -1, -1, 89, 90, + -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, + -1, 102, 103, 104, 105, -1, -1, 108, 109, 45, + 46, -1, -1, -1, 50, -1, 1, -1, 3, 4, + -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, + 76, -1, -1, -1, -1, -1, 82, -1, -1, 85, + 86, -1, -1, 89, 90, -1, -1, 93, -1, -1, + 45, 46, -1, -1, -1, 50, 102, 103, 104, 105, + -1, -1, 108, 109, 59, -1, -1, -1, -1, -1, + 65, 1, -1, 3, 4, -1, -1, 72, -1, -1, + -1, 76, -1, -1, -1, -1, -1, 82, -1, -1, + 85, 86, -1, -1, 89, 90, -1, -1, 93, -1, + -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, + 105, -1, -1, 108, 109, 45, 46, -1, -1, -1, + 50, -1, 1, -1, 3, 4, -1, -1, -1, 59, + -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, + -1, -1, 72, -1, -1, -1, 76, -1, -1, -1, + -1, -1, 82, -1, -1, 85, 86, -1, -1, 89, + 90, -1, -1, 93, -1, -1, 45, 46, -1, -1, + -1, 50, 102, 103, 104, 105, -1, -1, 108, 109, + 59, -1, -1, -1, -1, -1, 65, 1, -1, 3, + 4, -1, -1, 72, -1, -1, -1, 76, -1, -1, + -1, -1, -1, 82, -1, -1, 85, 86, -1, -1, + 89, 90, -1, -1, 93, -1, -1, -1, -1, -1, + -1, -1, -1, 102, 103, 104, 105, -1, -1, 108, + 109, 45, 46, -1, -1, -1, 50, -1, 1, -1, + 3, 4, -1, -1, -1, 59, -1, -1, -1, -1, + -1, 65, -1, -1, -1, -1, -1, -1, 72, -1, + -1, -1, 76, -1, -1, -1, -1, -1, 82, -1, + -1, 85, 86, -1, -1, 89, 90, -1, -1, 93, + -1, -1, 45, 46, -1, -1, -1, 50, 102, 103, + 104, 105, -1, -1, 108, 109, 59, -1, -1, -1, + -1, -1, 65, 1, -1, 3, 4, -1, -1, 72, + -1, -1, -1, 76, -1, -1, -1, -1, -1, 82, + -1, -1, 85, 86, -1, -1, 89, 90, -1, -1, + 93, -1, -1, -1, -1, -1, -1, -1, -1, 102, + 103, 104, 105, -1, -1, 108, 109, 45, 46, -1, + -1, -1, 50, -1, 1, -1, 3, 4, -1, -1, + -1, 59, -1, -1, -1, -1, -1, 65, -1, -1, + -1, -1, -1, -1, 72, -1, -1, -1, 76, -1, + -1, -1, -1, -1, 82, -1, -1, 85, 86, -1, + -1, 89, 90, -1, -1, 93, -1, -1, 45, 46, + -1, -1, -1, 50, 102, 103, 104, 105, -1, -1, + 108, 109, 59, -1, -1, -1, -1, -1, 65, 1, + -1, 3, 4, -1, -1, 72, -1, -1, -1, 76, + -1, -1, -1, -1, -1, 82, -1, -1, 85, 86, + -1, -1, 89, 90, -1, -1, 93, -1, -1, -1, + -1, -1, -1, -1, -1, 102, 103, 104, 105, -1, + -1, 108, 109, 45, 46, -1, -1, -1, 50, -1, + 1, -1, 3, 4, -1, -1, -1, 59, -1, -1, + -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, + 72, -1, -1, -1, 76, -1, -1, -1, -1, -1, + 82, -1, -1, 85, 86, -1, -1, 89, 90, -1, + -1, 93, -1, -1, 45, 46, -1, -1, -1, 50, + 102, 103, 104, 105, -1, -1, 108, 109, 59, -1, + -1, -1, -1, -1, 65, 1, -1, 3, 4, -1, + -1, 72, -1, -1, -1, 76, -1, -1, -1, -1, + -1, 82, -1, -1, 85, 86, -1, -1, 89, 90, + -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, + -1, 102, 103, 104, 105, -1, -1, 108, 109, 45, + 46, -1, -1, -1, 50, -1, 1, -1, 3, 4, + -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, + 76, -1, -1, -1, -1, -1, 82, -1, -1, 85, + 86, -1, -1, 89, 90, -1, -1, 93, -1, -1, + 45, 46, -1, -1, -1, 50, 102, 103, 104, 105, + -1, -1, 108, 109, 59, -1, -1, -1, -1, -1, + 65, 1, -1, 3, 4, -1, -1, 72, -1, -1, + -1, 76, -1, -1, -1, -1, -1, 82, -1, -1, + 85, 86, -1, -1, 89, 90, -1, -1, 93, -1, + -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, + 105, -1, -1, 108, 109, 45, 46, -1, -1, -1, + 50, -1, 1, -1, 3, 4, -1, -1, -1, 59, + -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, + -1, -1, 72, -1, -1, -1, 76, -1, -1, -1, + -1, -1, 82, -1, -1, 85, 86, -1, -1, 89, + 90, -1, -1, 93, -1, -1, 45, 46, -1, -1, + -1, 50, 102, 103, 104, 105, -1, -1, 108, 109, + 59, -1, -1, -1, -1, -1, 65, 1, -1, 3, + 4, -1, -1, 72, -1, -1, -1, 76, -1, -1, + -1, -1, -1, 82, -1, -1, 85, 86, -1, -1, + 89, 90, -1, -1, 93, -1, -1, -1, -1, -1, + -1, -1, -1, 102, 103, 104, 105, -1, -1, 108, + 109, 45, 46, -1, -1, -1, 50, -1, 1, -1, + 3, 4, -1, -1, -1, 59, -1, -1, -1, -1, + -1, 65, -1, -1, -1, -1, -1, -1, 72, -1, + -1, -1, 76, -1, -1, -1, -1, -1, 82, -1, + -1, 85, 86, -1, -1, 89, 90, -1, -1, 93, + -1, -1, 45, 46, -1, -1, -1, 50, 102, 103, + 104, 105, -1, -1, 108, 109, 59, -1, -1, -1, + -1, -1, 65, 1, -1, 3, 4, -1, -1, 72, + -1, -1, -1, 76, -1, -1, -1, -1, -1, 82, + -1, -1, 85, 86, -1, -1, 89, 90, -1, -1, + 93, -1, -1, -1, -1, -1, -1, -1, -1, 102, + 103, 104, 105, -1, -1, 108, 109, 45, 46, -1, + -1, -1, 50, -1, 1, -1, 3, 4, -1, -1, + -1, 59, -1, -1, -1, -1, -1, 65, -1, -1, + -1, -1, -1, -1, 72, -1, -1, -1, 76, -1, + -1, -1, -1, -1, 82, -1, -1, 85, 86, -1, + -1, 89, 90, -1, -1, 93, -1, -1, 45, 46, + -1, -1, -1, 50, 102, 103, 104, 105, -1, -1, + 108, 109, 59, -1, -1, -1, -1, -1, 65, 1, + -1, 3, 4, -1, -1, 72, -1, -1, -1, 76, + -1, -1, -1, -1, -1, 82, -1, -1, 85, 86, + -1, -1, 89, 90, -1, -1, 93, -1, -1, -1, + -1, -1, -1, -1, -1, 102, 103, 104, 105, -1, + -1, 108, 109, 45, 46, -1, -1, -1, 50, -1, + 1, -1, 3, 4, -1, -1, -1, 59, -1, -1, + -1, -1, -1, 65, -1, -1, -1, -1, -1, -1, + 72, -1, -1, -1, 76, -1, -1, -1, -1, -1, + 82, -1, -1, 85, 86, -1, -1, 89, 90, -1, + -1, 93, -1, -1, 45, 46, -1, -1, -1, 50, + 102, 103, 104, 105, -1, -1, 108, 109, 59, -1, + -1, -1, -1, -1, 65, 1, -1, 3, 4, -1, + -1, 72, -1, -1, -1, 76, -1, -1, -1, -1, + -1, 82, -1, -1, 85, 86, -1, -1, 89, 90, + -1, -1, 93, -1, -1, -1, -1, -1, -1, -1, + -1, 102, 103, 104, 105, -1, -1, 108, 109, 45, + 46, -1, -1, -1, 50, -1, 1, -1, 3, 4, + -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, + 76, -1, -1, -1, -1, -1, 82, -1, -1, 85, + 86, -1, -1, 89, 90, -1, -1, 93, -1, -1, + 45, 46, -1, -1, -1, 50, 102, 103, 104, 105, + -1, -1, 108, 109, 59, -1, -1, -1, -1, -1, + 65, 1, -1, 3, 4, -1, -1, 72, -1, -1, + -1, 76, -1, -1, -1, -1, -1, 82, -1, -1, + 85, 86, -1, -1, 89, 90, -1, -1, 93, -1, + -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, + 105, -1, -1, 108, 109, 45, 46, -1, -1, -1, + 50, -1, 1, -1, 3, 4, -1, -1, -1, 59, + -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, + -1, -1, 72, -1, -1, -1, 76, -1, -1, -1, + -1, -1, 82, -1, -1, 85, 86, -1, -1, 89, + 90, -1, -1, 93, -1, -1, 45, 46, -1, -1, + -1, 50, 102, 103, 104, 105, -1, -1, 108, 109, + 59, -1, -1, -1, -1, -1, 65, 1, -1, 3, + 4, -1, -1, 72, -1, -1, -1, 76, -1, -1, + -1, -1, -1, 82, -1, -1, 85, 86, -1, -1, + 89, 90, -1, -1, 93, -1, -1, -1, -1, -1, + -1, -1, -1, 102, 103, 104, 105, -1, -1, 108, + 109, 45, 46, -1, -1, -1, 50, -1, 1, -1, + 3, 4, -1, -1, -1, 59, -1, -1, -1, -1, + -1, 65, -1, -1, -1, -1, -1, -1, 72, -1, + -1, -1, 76, -1, -1, -1, -1, -1, 82, -1, + -1, 85, 86, -1, -1, 89, 90, -1, -1, 93, + -1, -1, 45, 46, -1, -1, -1, 50, 102, 103, + 104, 105, -1, -1, 108, 109, 59, -1, -1, -1, + -1, -1, 65, 1, -1, 3, 4, -1, -1, 72, + -1, -1, -1, 76, -1, -1, -1, -1, -1, 82, + -1, -1, 85, 86, -1, -1, 89, 90, -1, -1, + 93, -1, -1, -1, -1, -1, -1, -1, -1, 102, + 103, 104, 105, -1, -1, 108, 109, 45, 46, -1, + -1, -1, 50, -1, 1, -1, 3, 4, -1, -1, + -1, 59, -1, -1, -1, -1, -1, 65, -1, -1, + -1, -1, -1, -1, 72, -1, -1, -1, 76, -1, + -1, -1, -1, -1, 82, -1, -1, 85, 86, -1, + -1, 89, 90, -1, -1, 93, -1, -1, 45, 46, + -1, -1, -1, 50, 102, 103, 104, 105, -1, -1, + 108, 109, 59, -1, -1, -1, -1, -1, 65, -1, + 1, -1, -1, -1, -1, 72, -1, -1, -1, 76, + -1, -1, -1, -1, -1, 82, -1, -1, 85, 86, + -1, -1, 89, 90, -1, 1, 93, -1, -1, -1, + -1, -1, -1, -1, -1, 102, 103, 104, 105, -1, + -1, 108, 109, 44, 45, 46, -1, -1, -1, 50, + -1, -1, -1, -1, -1, -1, -1, -1, 59, -1, + -1, -1, -1, -1, 65, -1, -1, 1, -1, 45, + 46, 72, -1, -1, 50, 76, -1, -1, -1, -1, + -1, 82, -1, 59, 85, 86, -1, -1, -1, 65, + -1, -1, 93, -1, 3, 4, 72, -1, 99, -1, + 76, 102, 103, 104, 105, -1, 82, 108, 109, 85, + 86, 45, 46, -1, -1, -1, 50, 93, 94, -1, + -1, -1, -1, -1, -1, 59, 102, 103, 104, 105, + -1, 65, 108, 109, 1, -1, 45, 46, 72, -1, + -1, 50, 76, -1, -1, -1, -1, -1, 82, -1, + 59, 85, 86, -1, -1, -1, 65, -1, -1, 93, + 94, 3, 4, 72, -1, -1, -1, 76, 102, 103, + 104, 105, -1, 82, 108, 109, 85, 86, 45, 46, + 89, 90, -1, 50, 93, -1, 95, 96, -1, -1, + -1, 100, 59, 102, 103, 104, 105, -1, 65, 108, + 109, -1, -1, 45, 46, 72, -1, -1, 50, 76, + -1, -1, 3, 4, -1, 82, -1, 59, 85, 86, + -1, -1, -1, 65, -1, -1, 93, -1, -1, -1, + 72, -1, -1, -1, 76, 102, 103, 104, 105, -1, + 82, 108, 109, 85, 86, -1, -1, 89, 90, -1, + -1, 93, 94, -1, 45, 46, -1, -1, -1, 50, + 102, 103, 104, 105, -1, -1, 108, 109, 59, -1, + -1, -1, -1, -1, 65, -1, -1, 3, 4, -1, + -1, 72, -1, -1, -1, 76, -1, -1, -1, -1, + -1, 82, -1, -1, 85, 86, -1, -1, 89, 90, + -1, -1, 93, 94, -1, -1, -1, -1, -1, -1, + -1, 102, 103, 104, 105, -1, -1, 108, 109, 45, + 46, -1, -1, -1, 50, -1, -1, -1, 3, 4, + -1, -1, -1, 59, -1, -1, -1, -1, -1, 65, + -1, -1, -1, -1, -1, -1, 72, -1, -1, -1, + 76, -1, -1, -1, -1, -1, 82, -1, -1, 85, + 86, -1, -1, 89, 90, -1, -1, 93, 94, -1, + 45, 46, -1, -1, -1, 50, 102, 103, 104, 105, + -1, -1, 108, 109, 59, -1, -1, -1, -1, -1, + 65, -1, -1, 3, 4, -1, -1, 72, -1, -1, + -1, 76, -1, -1, -1, -1, -1, 82, -1, -1, + 85, 86, -1, -1, 89, 90, -1, -1, 93, 94, + -1, -1, -1, -1, -1, -1, -1, 102, 103, 104, + 105, -1, -1, 108, 109, 45, 46, -1, -1, -1, + 50, -1, -1, -1, -1, -1, -1, -1, -1, 59, + -1, -1, -1, -1, -1, 65, -1, -1, -1, -1, + -1, -1, 72, -1, -1, -1, 76, -1, -1, -1, + -1, -1, 82, -1, -1, 85, 86, -1, -1, 89, + 90, -1, -1, 93, -1, 44, 45, 46, -1, -1, + -1, 50, 102, 103, 104, 105, -1, -1, 108, 109, + 59, -1, -1, -1, -1, -1, 65, -1, -1, -1, + -1, -1, -1, 72, -1, -1, -1, 76, -1, -1, + -1, -1, -1, 82, -1, -1, 85, 86, -1, -1, + -1, -1, -1, -1, 93, -1, -1, -1, -1, -1, + -1, -1, -1, 102, 103, 104, 105, -1, -1, 108, + 109 +}; +#define YYPURE 1 + +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ +#line 3 "/usr/cygnus/gnupro-98r1/share/bison.simple" + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + 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, 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include +#else /* not sparc */ +#if defined (MSDOS) && !defined (__TURBOC__) +#include +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +#include + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#ifdef __cplusplus +extern "C" { +void *alloca (unsigned int); +}; +#else /* not __cplusplus */ +void *alloca (); +#endif /* not __cplusplus */ +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +int yyparse (void); +#endif + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(TO,FROM,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (to, from, count) + char *to; + char *from; + int count; +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *to, char *from, int count) +{ + register char *f = from; + register char *t = to; + register int i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +#line 196 "/usr/cygnus/gnupro-98r1/share/bison.simple" + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifdef __cplusplus +#define YYPARSE_PARAM_ARG void *YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#else /* not __cplusplus */ +#define YYPARSE_PARAM_ARG YYPARSE_PARAM +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif /* not __cplusplus */ +#else /* not YYPARSE_PARAM */ +#define YYPARSE_PARAM_ARG +#define YYPARSE_PARAM_DECL +#endif /* not YYPARSE_PARAM */ + +int +yyparse(YYPARSE_PARAM_ARG) + YYPARSE_PARAM_DECL +{ + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + int yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + int size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss, (char *)yyss1, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs, (char *)yyvs1, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls, (char *)yyls1, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + + + switch (yyn) { + +case 1: +#line 253 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{; + break;} +case 18: +#line 297 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_java_array_type (yyvsp[-2].node, -1); + CLASS_LOADED_P (yyval.node) = 1; + ; + break;} +case 19: +#line 302 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_unresolved_array_type (yyvsp[-2].node); ; + break;} +case 20: +#line 304 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_unresolved_array_type (yyvsp[-2].node); ; + break;} +case 21: +#line 306 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{RULE ("']' expected"); RECOVER;; + break;} +case 22: +#line 308 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{RULE ("']' expected"); RECOVER;; + break;} +case 26: +#line 323 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = make_qualified_name (yyvsp[-2].node, yyvsp[0].node, yyvsp[-1].operator.location); ; + break;} +case 28: +#line 332 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = NULL;; + break;} +case 36: +#line 344 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = NULL; + ; + break;} +case 37: +#line 348 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = NULL; + ; + break;} +case 40: +#line 360 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ ctxp->package = EXPR_WFL_NODE (yyvsp[-1].node); ; + break;} +case 41: +#line 362 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing name"); RECOVER;; + break;} +case 42: +#line 364 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 45: +#line 374 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree name = EXPR_WFL_NODE (yyvsp[-1].node), node, last_name; + int i = IDENTIFIER_LENGTH (name)-1; + 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 + (yyvsp[-1].node, "Ambiguous class: `%s' and `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (err)); + } + else + { + IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (last_name) = 1; + node = build_tree_list (yyvsp[-1].node, last_name); + TREE_CHAIN (node) = ctxp->import_list; + ctxp->import_list = node; + } + ; + break;} +case 46: +#line 403 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing name"); RECOVER;; + break;} +case 47: +#line 405 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 48: +#line 410 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree name = EXPR_WFL_NODE (yyvsp[-3].node); + tree node = build_tree_list (yyvsp[-3].node, NULL_TREE); + if (!IS_AN_IMPORT_ON_DEMAND_P (name)) + { + read_import_dir (yyvsp[-3].node); + IS_AN_IMPORT_ON_DEMAND_P (name) = 1; + } + TREE_CHAIN (node) = ctxp->import_demand_list; + ctxp->import_demand_list = node; + ; + break;} +case 49: +#line 422 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'*' expected"); RECOVER;; + break;} +case 50: +#line 424 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 51: +#line 429 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + maybe_generate_clinit (); + yyval.node = yyvsp[0].node; + ; + break;} +case 53: +#line 435 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = NULL; ; + break;} +case 54: +#line 437 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + YYERROR_NOW; + yyerror ("Class or interface declaration expected"); + ; + break;} +case 55: +#line 448 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.value = (1 << yyvsp[0].value); + ; + break;} +case 56: +#line 452 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + int acc = (1 << yyvsp[0].value); + if (yyval.value & acc) + parse_error_context + (ctxp->modifier_ctx [yyvsp[0].value], "Modifier `%s' declared twice", + java_accstring_lookup (acc)); + else + { + yyval.value |= acc; + } + ; + break;} +case 57: +#line 468 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ create_class (yyvsp[-4].value, yyvsp[-2].node, yyvsp[-1].node, yyvsp[0].node); ; + break;} +case 58: +#line 470 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = yyvsp[0].node; + ; + break;} +case 59: +#line 474 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ create_class (0, yyvsp[-2].node, yyvsp[-1].node, yyvsp[0].node); ; + break;} +case 60: +#line 476 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = yyvsp[0].node; + ; + break;} +case 61: +#line 480 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing class name"); RECOVER;; + break;} +case 62: +#line 482 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing class name"); RECOVER;; + break;} +case 63: +#line 484 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{if (!ctxp->class_err) yyerror ("'{' expected"); DRECOVER(class1);; + break;} +case 64: +#line 486 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{if (!ctxp->class_err) yyerror ("'{' expected"); RECOVER;; + break;} +case 65: +#line 490 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = NULL; ; + break;} +case 66: +#line 492 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = yyvsp[0].node; ; + break;} +case 67: +#line 494 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'{' expected"); ctxp->class_err=1;; + break;} +case 68: +#line 496 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing super class name"); ctxp->class_err=1;; + break;} +case 69: +#line 500 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = NULL_TREE; ; + break;} +case 70: +#line 502 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = yyvsp[0].node; ; + break;} +case 71: +#line 504 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + ctxp->class_err=1; + yyerror ("Missing interface name"); + ; + break;} +case 72: +#line 512 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + ctxp->interface_number = 1; + yyval.node = build_tree_list (yyvsp[0].node, NULL_TREE); + ; + break;} +case 73: +#line 517 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + ctxp->interface_number++; + yyval.node = chainon (yyvsp[-2].node, build_tree_list (yyvsp[0].node, NULL_TREE)); + ; + break;} +case 74: +#line 522 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing interface name"); RECOVER;; + break;} +case 75: +#line 527 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = ctxp->current_parsed_class; ; + break;} +case 76: +#line 529 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = ctxp->current_parsed_class; ; + break;} +case 87: +#line 554 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ register_fields (0, yyvsp[-2].node, yyvsp[-1].node); ; + break;} +case 88: +#line 556 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + int acc_count = 0; + + check_modifiers + ("Illegal modifier `%s' for field declaration", + yyvsp[-3].value, FIELD_MODIFIERS); + check_modifiers_consistency (yyvsp[-3].value); + register_fields (yyvsp[-3].value, yyvsp[-2].node, yyvsp[-1].node); + ; + break;} +case 90: +#line 571 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = chainon (yyvsp[-2].node, yyvsp[0].node); ; + break;} +case 91: +#line 573 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 92: +#line 578 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_tree_list (yyvsp[0].node, NULL_TREE); ; + break;} +case 93: +#line 580 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + if (java_error_count) + yyvsp[0].node = NULL_TREE; + yyval.node = build_tree_list + (yyvsp[-2].node, build_assignment (yyvsp[-1].operator.token, yyvsp[-1].operator.location, yyvsp[-2].node, yyvsp[0].node)); + ; + break;} +case 94: +#line 587 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyerror ("Missing variable initializer"); + yyval.node = build_tree_list (yyvsp[-2].node, NULL_TREE); + RECOVER; + ; + break;} +case 95: +#line 593 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyerror ("';' expected"); + yyval.node = build_tree_list (yyvsp[-3].node, NULL_TREE); + RECOVER; + ; + break;} +case 97: +#line 603 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = NULL; /* FIXME */ + ; + break;} +case 98: +#line 607 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Invalid declaration"); DRECOVER(vdi);; + break;} +case 99: +#line 609 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("']' expected"); DRECOVER(vdi);; + break;} +case 100: +#line 611 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Unbalanced ']'"); DRECOVER(vdi);; + break;} +case 102: +#line 617 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = NULL; ; + break;} +case 103: +#line 623 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + current_function_decl = yyvsp[0].node; + source_start_java_method (current_function_decl); + ; + break;} +case 104: +#line 628 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + BLOCK_EXPR_BODY + (DECL_FUNCTION_BODY (current_function_decl)) = yyvsp[0].node; + maybe_absorb_scoping_blocks (); + exit_block (); /* Exit function's body. */ + + /* Merge last line of the function with first line, + directly in the function decl. It will be used to + emit correct debug info. */ + DECL_SOURCE_LINE_MERGE (current_function_decl, + ctxp->last_ccb_indent1); + ; + break;} +case 105: +#line 641 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{YYNOT_TWICE yyerror ("'{' expected"); RECOVER;; + break;} +case 106: +#line 646 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = method_header (0, yyvsp[-2].node, yyvsp[-1].node, NULL); ; + break;} +case 107: +#line 648 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = method_header (0, void_type_node, yyvsp[-1].node, NULL); ; + break;} +case 108: +#line 650 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = method_header (yyvsp[-3].value, yyvsp[-2].node, yyvsp[-1].node, NULL); ; + break;} +case 109: +#line 652 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = method_header (yyvsp[-3].value, void_type_node, yyvsp[-1].node, NULL); ; + break;} +case 110: +#line 654 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{RECOVER;; + break;} +case 111: +#line 656 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{RECOVER;; + break;} +case 112: +#line 658 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Identifier expected"); RECOVER;; + break;} +case 113: +#line 660 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Identifier expected"); RECOVER;; + break;} +case 114: +#line 662 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyerror ("Invalid method declaration, return type required"); + RECOVER; + ; + break;} +case 115: +#line 670 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = method_declarator (yyvsp[-2].node, NULL_TREE); ; + break;} +case 116: +#line 672 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = method_declarator (yyvsp[-3].node, yyvsp[-1].node); ; + break;} +case 117: +#line 674 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + /* Issue a warning here: obsolete declaration. FIXME */ + yyval.node = NULL; /* FIXME */ + ; + break;} +case 118: +#line 679 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); DRECOVER(method_declarator);; + break;} +case 119: +#line 681 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("']' expected"); RECOVER;; + break;} +case 120: +#line 686 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + ctxp->formal_parameter_number = 1; + ; + break;} +case 121: +#line 690 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + ctxp->formal_parameter_number += 1; + yyval.node = chainon (yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 122: +#line 695 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing formal parameter term"); RECOVER;; + break;} +case 123: +#line 700 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_tree_list (yyvsp[0].node, yyvsp[-1].node); + ; + break;} +case 124: +#line 704 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", yyvsp[-2].value)); + yyval.node = NULL; /* FIXME */ + ; + break;} +case 125: +#line 709 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing identifier"); RECOVER;; + break;} +case 126: +#line 711 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", yyvsp[-2].value)); + yyerror ("Missing identifier"); RECOVER; + ; + break;} +case 129: +#line 720 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing class type term"); RECOVER;; + break;} +case 132: +#line 727 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing class type term"); RECOVER;; + break;} +case 135: +#line 734 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = NULL_TREE; ; + break;} +case 136: +#line 740 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("STATIC_INITIALIZER"); + ; + break;} +case 137: +#line 744 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("STATIC_INITIALIZER"); + ; + break;} +case 138: +#line 751 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", yyvsp[0].value)); + ; + break;} +case 139: +#line 763 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("CONSTRUCTOR_DECLARATION"); + ; + break;} +case 140: +#line 767 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", yyvsp[-3].value)); + RULE ("CONSTRUCTOR_DECLARATION (modifier)"); + ; + break;} +case 141: +#line 773 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("CONSTRUCTOR_DECLARATION"); + ; + break;} +case 142: +#line 778 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", yyvsp[-4].value)); + RULE ("CONSTRUCTOR_DECLARATION (modifier)"); + ; + break;} +case 152: +#line 806 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{RULE ("explicit_constructor_invocation (X.super)");; + break;} +case 153: +#line 811 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = yyvsp[0].operator.location; + yyval.node = wfl; + ; + break;} +case 154: +#line 817 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = yyvsp[0].operator.location; + yyval.node = wfl; + ; + break;} +case 155: +#line 828 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ create_interface (0, yyvsp[0].node, NULL_TREE); ; + break;} +case 156: +#line 830 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = yyvsp[0].node; + ; + break;} +case 157: +#line 834 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ create_interface (yyvsp[-2].value, yyvsp[0].node, NULL_TREE); ; + break;} +case 158: +#line 836 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = yyvsp[0].node; + ; + break;} +case 159: +#line 840 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ create_interface (0, yyvsp[-1].node, yyvsp[0].node); ; + break;} +case 160: +#line 842 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = yyvsp[0].node; + ; + break;} +case 161: +#line 846 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ create_interface (yyvsp[-3].value, yyvsp[-1].node, yyvsp[0].node); ; + break;} +case 162: +#line 848 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = yyvsp[0].node; + ; + break;} +case 163: +#line 852 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("(here)'{' expected"); RECOVER;; + break;} +case 164: +#line 854 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("(there)'{' expected"); RECOVER;; + break;} +case 165: +#line 859 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + ctxp->interface_number = 1; + yyval.node = build_tree_list (yyvsp[0].node, NULL_TREE); + ; + break;} +case 166: +#line 864 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + ctxp->interface_number++; + yyval.node = chainon (yyvsp[-2].node, build_tree_list (yyvsp[0].node, NULL_TREE)); + ; + break;} +case 167: +#line 869 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Invalid interface type"); RECOVER;; + break;} +case 168: +#line 871 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 169: +#line 876 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = NULL_TREE; ; + break;} +case 170: +#line 878 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = NULL_TREE; ; + break;} +case 178: +#line 899 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + check_abstract_method_header (yyvsp[-1].node); + current_function_decl = NULL_TREE; /* FIXME ? */ + ; + break;} +case 179: +#line 904 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 180: +#line 910 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("ARRAY_INITIALIZER (empty)"); + ; + break;} +case 181: +#line 914 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("ARRAY_INITIALIZER (variable)"); + ; + break;} +case 182: +#line 918 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("ARRAY_INITIALIZER (,)"); + ; + break;} +case 183: +#line 922 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("ARRAY_INITIALIZER (variable, ,)"); + ; + break;} +case 186: +#line 931 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 187: +#line 937 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = size_zero_node; ; + break;} +case 188: +#line 939 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ enter_block (); ; + break;} +case 189: +#line 942 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + maybe_absorb_scoping_blocks (); + yyval.node = exit_block (); + ; + break;} +case 193: +#line 956 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = java_method_add_stmt (current_function_decl, yyvsp[0].node); ; + break;} +case 196: +#line 966 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ declare_local_variables (0, yyvsp[-1].node, yyvsp[0].node); ; + break;} +case 197: +#line 968 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ declare_local_variables (yyvsp[-2].value, yyvsp[-1].node, yyvsp[0].node); ; + break;} +case 199: +#line 974 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (labeled)"); ; + break;} +case 200: +#line 976 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (if-then)"); ; + break;} +case 201: +#line 978 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (if-then-else)"); ; + break;} +case 202: +#line 980 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (while)"); ; + break;} +case 203: +#line 982 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + /* If the for loop is unlabeled, we must return the + block it was defined it. It our last chance to + get a hold on it. */ + if (!LOOP_HAS_LABEL_P (yyval.node)) + yyval.node = exit_block (); + ; + break;} +case 205: +#line 994 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("NSI STATEMENT (labeled)"); ; + break;} +case 206: +#line 996 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("NSI STATEMENT (if-then-else)"); ; + break;} +case 207: +#line 998 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("NSI STATEMENT (while)"); ; + break;} +case 208: +#line 1000 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("NSI STATEMENT (for)"); ; + break;} +case 209: +#line 1005 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (block)"); ; + break;} +case 210: +#line 1007 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (empty)"); ; + break;} +case 211: +#line 1009 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (expression)"); ; + break;} +case 212: +#line 1011 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (switch)"); ; + break;} +case 213: +#line 1013 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (do)"); ; + break;} +case 214: +#line 1015 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (break)"); ; + break;} +case 215: +#line 1017 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (continue)"); ; + break;} +case 217: +#line 1020 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (synchronized)"); ; + break;} +case 218: +#line 1022 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (throw)"); ; + break;} +case 219: +#line 1024 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ RULE ("STATEMENT (try)"); ; + break;} +case 220: +#line 1029 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = size_zero_node; ; + break;} +case 221: +#line 1034 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_labeled_block (EXPR_WFL_LINECOL (yyvsp[-1].node), + EXPR_WFL_NODE (yyvsp[-1].node), yyvsp[-1].node); + pushlevel (2); + push_labeled_block (yyval.node); + PUSH_LABELED_BLOCK (yyval.node); + ; + break;} +case 222: +#line 1045 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = complete_labeled_statement (yyvsp[-1].node, yyvsp[0].node); + pop_labeled_block (); + POP_LABELED_BLOCK (); + ; + break;} +case 223: +#line 1051 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("':' expected"); RECOVER;; + break;} +case 224: +#line 1056 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = complete_labeled_statement (yyvsp[-1].node, yyvsp[0].node); + pop_labeled_block (); + POP_LABELED_BLOCK (); + ; + break;} +case 225: +#line 1067 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + /* We have a statement. Generate a WFL around it so + we can debug it */ + yyval.node = build_expr_wfl (yyvsp[-1].node, input_filename, lineno, 0); + /* We know we have a statement, so set the debug + info to be eventually generate here. */ + yyval.node = JAVA_MAYBE_GENERATE_DEBUG_INFO (yyval.node); + ; + break;} +case 226: +#line 1076 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + if (ctxp->prevent_ese != lineno) + yyerror ("Invalid expression statement"); + DRECOVER (expr_stmt); + ; + break;} +case 227: +#line 1082 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + if (ctxp->prevent_ese != lineno) + yyerror ("Invalid expression statement"); + DRECOVER (expr_stmt); + ; + break;} +case 228: +#line 1088 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + if (ctxp->prevent_ese != lineno) + yyerror ("Invalid expression statement"); + DRECOVER (expr_stmt); + ; + break;} +case 229: +#line 1094 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); RECOVER;; + break;} +case 230: +#line 1096 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 231: +#line 1098 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); RECOVER;; + break;} +case 232: +#line 1100 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 233: +#line 1102 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); RECOVER;; + break;} +case 234: +#line 1104 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); RECOVER;; + break;} +case 235: +#line 1106 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); RECOVER;; + break;} +case 236: +#line 1108 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 237: +#line 1110 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 239: +#line 1116 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("++INCREMENT"); + ; + break;} +case 240: +#line 1120 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("--DECREMENT"); + ; + break;} +case 241: +#line 1124 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("INCREMENT++"); + ; + break;} +case 242: +#line 1128 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("DECREMENT--"); + ; + break;} +case 244: +#line 1133 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + RULE ("INSTANCE CREATION"); + ; + break;} +case 245: +#line 1140 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_if_else_statement (yyvsp[-3].operator.location, yyvsp[-2].node, yyvsp[0].node, NULL_TREE); ; + break;} +case 246: +#line 1142 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); RECOVER;; + break;} +case 247: +#line 1144 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 248: +#line 1146 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); RECOVER;; + break;} +case 249: +#line 1151 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_if_else_statement (yyvsp[-5].operator.location, yyvsp[-4].node, yyvsp[-2].node, yyvsp[0].node); ; + break;} +case 250: +#line 1156 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_if_else_statement (yyvsp[-5].operator.location, yyvsp[-4].node, yyvsp[-2].node, yyvsp[0].node); ; + break;} +case 252: +#line 1162 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); RECOVER;; + break;} +case 253: +#line 1164 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term or ')'"); DRECOVER(switch_statement);; + break;} +case 254: +#line 1166 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'{' expected"); RECOVER;; + break;} +case 266: +#line 1195 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing or invalid constant expression"); RECOVER;; + break;} +case 267: +#line 1197 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("':' expected"); RECOVER;; + break;} +case 268: +#line 1199 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("':' expected"); RECOVER;; + break;} +case 269: +#line 1204 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree body = build_loop_body (yyvsp[-2].operator.location, yyvsp[-1].node, 0); + yyval.node = build_new_loop (body); + ; + break;} +case 270: +#line 1212 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = complete_loop_body (0, NULL_TREE, yyvsp[0].node, 0); ; + break;} +case 271: +#line 1214 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{YYERROR_NOW; yyerror ("'(' expected"); RECOVER;; + break;} +case 272: +#line 1216 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term and ')' expected"); RECOVER;; + break;} +case 273: +#line 1218 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); RECOVER;; + break;} +case 274: +#line 1223 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = complete_loop_body (0, NULL_TREE, yyvsp[0].node, 0); ; + break;} +case 275: +#line 1228 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree body = build_loop_body (0, NULL_TREE, 1); + yyval.node = build_new_loop (body); + ; + break;} +case 276: +#line 1237 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = complete_loop_body (yyvsp[-3].operator.location, yyvsp[-2].node, yyvsp[-5].node, 1); ; + break;} +case 277: +#line 1242 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = complete_for_loop (EXPR_WFL_LINECOL (yyvsp[-4].node), yyvsp[-4].node, yyvsp[-2].node, yyvsp[0].node);; + break;} +case 278: +#line 1244 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = complete_for_loop (0, NULL_TREE, yyvsp[-2].node, yyvsp[0].node); + /* We have not condition, so we get rid of the EXIT_EXPR */ + LOOP_EXPR_BODY_CONDITION_EXPR (LOOP_EXPR_BODY (yyval.node), 0) = + size_zero_node; + ; + break;} +case 279: +#line 1251 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Invalid control expression"); RECOVER;; + break;} +case 280: +#line 1253 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Invalid update expression"); RECOVER;; + break;} +case 281: +#line 1255 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Invalid update expression"); RECOVER;; + break;} +case 282: +#line 1260 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = complete_for_loop (EXPR_WFL_LINECOL (yyvsp[-4].node), yyvsp[-4].node, yyvsp[-2].node, yyvsp[0].node);; + break;} +case 283: +#line 1262 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = complete_for_loop (0, NULL_TREE, yyvsp[-2].node, yyvsp[0].node); + /* We have not condition, so we get rid of the EXIT_EXPR */ + LOOP_EXPR_BODY_CONDITION_EXPR (LOOP_EXPR_BODY (yyval.node), 0) = + size_zero_node; + ; + break;} +case 284: +#line 1272 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + /* This scope defined for local variable that may be + defined within the scope of the for loop */ + enter_block (); + ; + break;} +case 285: +#line 1278 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); DRECOVER(for_1);; + break;} +case 286: +#line 1280 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Invalid init statement"); RECOVER;; + break;} +case 287: +#line 1285 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + /* We now declare the loop body. The loop is + declared as a for loop. */ + tree body = build_loop_body (0, NULL_TREE, 0); + yyval.node = build_new_loop (body); + IS_FOR_LOOP_P (yyval.node) = 1; + /* The loop is added to the current block the for + statement is defined within */ + java_method_add_stmt (current_function_decl, yyval.node); + ; + break;} +case 288: +#line 1297 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = size_zero_node; ; + break;} +case 289: +#line 1299 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + /* Init statement recorded within the previously + defined block scope */ + yyval.node = java_method_add_stmt (current_function_decl, yyvsp[0].node); + ; + break;} +case 290: +#line 1305 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + /* Local variable are recorded within the previously + defined block scope */ + yyval.node = NULL_TREE; + ; + break;} +case 291: +#line 1311 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); DRECOVER(for_init_1);; + break;} +case 292: +#line 1315 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = size_zero_node;; + break;} +case 293: +#line 1317 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_debugable_stmt (BUILD_LOCATION (), yyvsp[0].node); ; + break;} +case 294: +#line 1322 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = add_stmt_to_compound (NULL_TREE, NULL_TREE, yyvsp[0].node); ; + break;} +case 295: +#line 1324 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = add_stmt_to_compound (yyvsp[-2].node, NULL_TREE, yyvsp[0].node); ; + break;} +case 296: +#line 1326 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 297: +#line 1331 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_bc_statement (yyvsp[-1].operator.location, 1, NULL_TREE); ; + break;} +case 298: +#line 1333 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_bc_statement (yyvsp[-2].operator.location, 1, yyvsp[-1].node); ; + break;} +case 299: +#line 1335 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 300: +#line 1337 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 301: +#line 1342 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_bc_statement (yyvsp[-1].operator.location, 0, NULL_TREE); ; + break;} +case 302: +#line 1344 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_bc_statement (yyvsp[-2].operator.location, 0, yyvsp[-1].node); ; + break;} +case 303: +#line 1346 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 304: +#line 1348 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 305: +#line 1353 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_return (yyvsp[-1].operator.location, NULL_TREE); ; + break;} +case 306: +#line 1355 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_return (yyvsp[-2].operator.location, yyvsp[-1].node); ; + break;} +case 307: +#line 1357 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 308: +#line 1359 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 310: +#line 1365 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 311: +#line 1367 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("';' expected"); RECOVER;; + break;} +case 313: +#line 1373 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'{' expected"); RECOVER;; + break;} +case 314: +#line 1375 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); RECOVER;; + break;} +case 315: +#line 1377 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 316: +#line 1379 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 317: +#line 1384 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", yyvsp[0].value)); + ; + break;} +case 321: +#line 1394 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'{' expected"); DRECOVER (try_statement);; + break;} +case 325: +#line 1405 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); RECOVER;; + break;} +case 326: +#line 1407 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); DRECOVER (1);; + break;} +case 327: +#line 1409 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); DRECOVER (2);; + break;} +case 329: +#line 1415 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'{' expected"); RECOVER; ; + break;} +case 333: +#line 1427 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_this (yyvsp[0].operator.location); ; + break;} +case 334: +#line 1429 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = yyvsp[-1].node;; + break;} +case 343: +#line 1445 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); RECOVER;; + break;} +case 344: +#line 1447 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'class' or 'this' expected" ); RECOVER;; + break;} +case 345: +#line 1449 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'class' expected" ); RECOVER;; + break;} +case 346: +#line 1451 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'class' expected" ); RECOVER;; + break;} +case 347: +#line 1456 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_method_invocation (yyvsp[-3].node, yyvsp[-1].node); + TREE_SET_CODE (yyval.node, JAVA_NEW_CLASS_EXPR); + ; + break;} +case 348: +#line 1461 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_method_invocation (yyvsp[-2].node, NULL_TREE); + TREE_SET_CODE (yyval.node, JAVA_NEW_CLASS_EXPR); + ; + break;} +case 349: +#line 1469 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = yyvsp[-4].node;; + break;} +case 350: +#line 1471 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = yyvsp[-3].node;; + break;} +case 355: +#line 1480 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); DRECOVER(new_1);; + break;} +case 356: +#line 1482 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); RECOVER;; + break;} +case 357: +#line 1484 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' or term expected"); RECOVER;; + break;} +case 358: +#line 1486 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("')' expected"); RECOVER;; + break;} +case 359: +#line 1488 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{YYERROR_NOW; yyerror ("Identifier expected"); RECOVER;; + break;} +case 360: +#line 1490 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'(' expected"); RECOVER;; + break;} +case 363: +#line 1500 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = tree_cons (NULL_TREE, yyvsp[0].node, NULL_TREE); + ctxp->formal_parameter_number = 1; + ; + break;} +case 364: +#line 1505 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + ctxp->formal_parameter_number += 1; + yyval.node = tree_cons (NULL_TREE, yyvsp[0].node, yyvsp[-2].node); + ; + break;} +case 365: +#line 1510 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 366: +#line 1515 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_newarray_node (yyvsp[-1].node, yyvsp[0].node, 0); ; + break;} +case 367: +#line 1517 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_newarray_node (yyvsp[-1].node, yyvsp[0].node, 0); ; + break;} +case 368: +#line 1519 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_newarray_node (yyvsp[-2].node, yyvsp[-1].node, ctxp->osb_number); ; + break;} +case 369: +#line 1521 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_newarray_node (yyvsp[-2].node, yyvsp[-1].node, ctxp->osb_number); ; + break;} +case 370: +#line 1525 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = yyvsp[-2].node;; + break;} +case 371: +#line 1527 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = yyvsp[-2].node;; + break;} +case 372: +#line 1529 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("'[' expected"); DRECOVER ("]");; + break;} +case 373: +#line 1531 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("']' expected"); RECOVER;; + break;} +case 374: +#line 1536 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_tree_list (NULL_TREE, yyvsp[0].node); ; + break;} +case 375: +#line 1538 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = tree_cons (NULL_TREE, yyvsp[0].node, yyval.node); ; + break;} +case 376: +#line 1543 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + EXPR_WFL_LINECOL (yyvsp[-1].node) = yyvsp[-2].operator.location; + yyval.node = yyvsp[-1].node; + ; + break;} +case 377: +#line 1548 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("']' expected"); RECOVER;; + break;} +case 378: +#line 1550 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyerror ("Missing term"); + yyerror ("']' expected"); + RECOVER; + ; + break;} +case 379: +#line 1559 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ ctxp->osb_number = 1; ; + break;} +case 380: +#line 1561 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ ctxp->osb_number++; ; + break;} +case 381: +#line 1563 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyerror ("']' expected"); RECOVER;; + break;} +case 382: +#line 1568 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = make_qualified_primary (yyvsp[-2].node, yyvsp[0].node, yyvsp[-1].operator.location); ; + break;} +case 383: +#line 1570 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree super_wfl = + build_wfl_node (super_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (super_wfl) = yyvsp[-2].operator.location; + yyval.node = make_qualified_name (super_wfl, yyvsp[0].node, yyvsp[-1].operator.location); + ; + break;} +case 384: +#line 1577 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Field expected"); DRECOVER (super_field_acces);; + break;} +case 385: +#line 1582 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_method_invocation (yyvsp[-2].node, NULL_TREE); ; + break;} +case 386: +#line 1584 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_method_invocation (yyvsp[-3].node, yyvsp[-1].node); ; + break;} +case 387: +#line 1586 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree invok = build_method_invocation (yyvsp[-2].node, NULL_TREE); + yyval.node = make_qualified_primary (yyvsp[-4].node, invok, yyvsp[-3].operator.location); + ; + break;} +case 388: +#line 1591 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree invok = build_method_invocation (yyvsp[-3].node, yyvsp[-1].node); + yyval.node = make_qualified_primary (yyvsp[-5].node, invok, yyvsp[-4].operator.location); + ; + break;} +case 389: +#line 1596 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree invok; + tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = yyvsp[-4].operator.location; + invok = build_method_invocation (yyvsp[-2].node, NULL_TREE); + yyval.node = make_qualified_primary (wfl, invok, yyvsp[-3].operator.location); + ; + break;} +case 390: +#line 1604 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree invok; + tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = yyvsp[-5].operator.location; + invok = build_method_invocation (yyvsp[-3].node, yyvsp[-1].node); + yyval.node = make_qualified_primary (wfl, invok, yyvsp[-4].operator.location); + ; + break;} +case 391: +#line 1616 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyerror ("'(' expected"); DRECOVER (method_invocation); ; + break;} +case 392: +#line 1618 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyerror ("'(' expected"); DRECOVER (method_invocation); ; + break;} +case 393: +#line 1623 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_array_ref (yyvsp[-2].operator.location, yyvsp[-3].node, yyvsp[-1].node); ; + break;} +case 394: +#line 1625 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_array_ref (yyvsp[-2].operator.location, yyvsp[-3].node, yyvsp[-1].node); ; + break;} +case 395: +#line 1627 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyerror ("Missing term and ']' expected"); + DRECOVER(array_access); + ; + break;} +case 396: +#line 1632 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyerror ("']' expected"); + DRECOVER(array_access); + ; + break;} +case 397: +#line 1637 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyerror ("Missing term and ']' expected"); + DRECOVER(array_access); + ; + break;} +case 398: +#line 1642 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyerror ("']' expected"); + DRECOVER(array_access); + ; + break;} +case 403: +#line 1657 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_incdec (yyvsp[0].operator.token, yyvsp[0].operator.location, yyvsp[-1].node, 1); ; + break;} +case 404: +#line 1662 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_incdec (yyvsp[0].operator.token, yyvsp[0].operator.location, yyvsp[-1].node, 1); ; + break;} +case 407: +#line 1669 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = build_unaryop (yyvsp[-1].operator.token, yyvsp[-1].operator.location, yyvsp[0].node); ; + break;} +case 408: +#line 1671 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = build_unaryop (yyvsp[-1].operator.token, yyvsp[-1].operator.location, yyvsp[0].node); ; + break;} +case 410: +#line 1674 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER; + break;} +case 411: +#line 1676 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER; + break;} +case 412: +#line 1681 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = build_incdec (yyvsp[-1].operator.token, yyvsp[-1].operator.location, yyvsp[0].node, 0); ; + break;} +case 413: +#line 1683 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER; + break;} +case 414: +#line 1688 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = build_incdec (yyvsp[-1].operator.token, yyvsp[-1].operator.location, yyvsp[0].node, 0); ; + break;} +case 415: +#line 1690 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER; + break;} +case 417: +#line 1696 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = build_unaryop (yyvsp[-1].operator.token, yyvsp[-1].operator.location, yyvsp[0].node); ; + break;} +case 418: +#line 1698 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyval.node = build_unaryop (yyvsp[-1].operator.token, yyvsp[-1].operator.location, yyvsp[0].node); ; + break;} +case 420: +#line 1701 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER; + break;} +case 421: +#line 1703 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER; + break;} +case 422: +#line 1708 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + tree type = yyvsp[-3].node; + while (ctxp->osb_number--) + type = build_java_array_type (type, -1); + yyval.node = build_cast (yyvsp[-4].operator.location, type, yyvsp[0].node); + ; + break;} +case 423: +#line 1715 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_cast (yyvsp[-3].operator.location, yyvsp[-2].node, yyvsp[0].node); ; + break;} +case 424: +#line 1717 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_cast (yyvsp[-3].operator.location, yyvsp[-2].node, yyvsp[0].node); ; + break;} +case 425: +#line 1719 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + char *ptr; + while (ctxp->osb_number--) + obstack_1grow (&temporary_obstack, '['); + obstack_grow0 (&temporary_obstack, + IDENTIFIER_POINTER (EXPR_WFL_NODE (yyvsp[-3].node)), + IDENTIFIER_LENGTH (EXPR_WFL_NODE (yyvsp[-3].node))); + ptr = obstack_finish (&temporary_obstack); + EXPR_WFL_NODE (yyvsp[-3].node) = get_identifier (ptr); + yyval.node = build_cast (yyvsp[-4].operator.location, yyvsp[-3].node, yyvsp[0].node); + ; + break;} +case 426: +#line 1731 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("']' expected, invalid type expression");; + break;} +case 427: +#line 1733 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + if (ctxp->prevent_ese != lineno) + yyerror ("Invalid type expression"); RECOVER; + RECOVER; + ; + break;} +case 428: +#line 1739 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 429: +#line 1741 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 430: +#line 1743 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 432: +#line 1749 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), + yyvsp[-1].operator.location, yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 433: +#line 1754 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 434: +#line 1759 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 435: +#line 1764 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 436: +#line 1766 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 437: +#line 1768 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 439: +#line 1774 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 440: +#line 1779 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 441: +#line 1784 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 442: +#line 1786 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 444: +#line 1792 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 445: +#line 1797 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 446: +#line 1802 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 447: +#line 1807 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 448: +#line 1809 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 449: +#line 1811 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 451: +#line 1817 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 452: +#line 1822 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 453: +#line 1827 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 454: +#line 1832 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 456: +#line 1838 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 457: +#line 1840 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 458: +#line 1842 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 459: +#line 1844 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 460: +#line 1846 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Invalid reference type"); RECOVER;; + break;} +case 462: +#line 1852 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 463: +#line 1857 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 464: +#line 1862 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 465: +#line 1864 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 467: +#line 1870 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 468: +#line 1875 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 470: +#line 1881 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 471: +#line 1886 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 473: +#line 1892 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 474: +#line 1897 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 476: +#line 1903 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 477: +#line 1908 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 479: +#line 1914 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + yyval.node = build_binop (BINOP_LOOKUP (yyvsp[-1].operator.token), yyvsp[-1].operator.location, + yyvsp[-2].node, yyvsp[0].node); + ; + break;} +case 480: +#line 1919 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); RECOVER;; + break;} +case 483: +#line 1926 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + YYERROR_NOW; + yyerror ("Missing term"); + DRECOVER (1); + ; + break;} +case 484: +#line 1932 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); DRECOVER (2);; + break;} +case 485: +#line 1934 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{yyerror ("Missing term"); DRECOVER (3);; + break;} +case 488: +#line 1944 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ yyval.node = build_assignment (yyvsp[-1].operator.token, yyvsp[-1].operator.location, yyvsp[-2].node, yyvsp[0].node); ; + break;} +case 489: +#line 1946 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" +{ + if (ctxp->prevent_ese != lineno) + yyerror ("Missing term"); + DRECOVER (assign); + ; + break;} +} + /* the action file gets copied in in place of this dollarsign */ +#line 498 "/usr/cygnus/gnupro-98r1/share/bison.simple" + + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} +#line 1972 "/nfs/hoser/beer/java/egcs/gcc/java/parse.y" + + + +#include "lex.c" + +/* 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; + +/* Create a new parser context and make it the current one. */ + +void +java_push_parser_context () +{ + struct parser_ctxt *new = + (struct parser_ctxt *)malloc(sizeof (struct parser_ctxt)); + + bzero (new, sizeof (struct parser_ctxt)); + new->next = ctxp; + ctxp = new; + if (ctxp->next) + ctxp->incomplete_class = ctxp->next->incomplete_class; +} + +void +java_parser_context_save_global () +{ + ctxp->finput = finput; + ctxp->lineno = lineno; + ctxp->current_class = current_class; + ctxp->filename = input_filename; + ctxp->current_function_decl = current_function_decl; +} + +void +java_parser_context_restore_global () +{ + finput = ctxp->finput; + lineno = ctxp->lineno; + current_class = ctxp->current_class; + input_filename = ctxp->filename; + current_function_decl = ctxp->current_function_decl; +} + +void +java_pop_parser_context () +{ + tree current; + struct parser_ctxt *toFree = ctxp; + struct parser_ctxt *next = ctxp->next; + + if (next) + { + next->incomplete_class = ctxp->incomplete_class; + lineno = ctxp->lineno; + finput = ctxp->finput; + current_class = ctxp->current_class; + } + + /* 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_PURPOSE (current)) = 0; + + /* And restore those of the previous context */ + if (ctxp = next) + for (current = ctxp->import_list; current; current = TREE_CHAIN (current)) + IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (TREE_PURPOSE (current)) = 1; + + free (toFree); +} + +static int do_warning = 0; + +void +yyerror (msg) + char *msg; +{ + static java_lc elc; + static int prev_lineno; + static char *prev_msg; + + int i, save_lineno; + char *remainder, *code_from_source; + extern struct obstack temporary_obstack; + + if (!force_error && prev_lineno == lineno) + return; + + /* Save current error location but report latter, when the context is + richer. */ + if (ctxp->java_error_flag == 0) + { + ctxp->java_error_flag = 1; + elc = ctxp->elc; + /* Do something to use the previous line if we're reaching the + end of the file... */ +#ifdef VERBOSE_SKELETON + printf ("* Error detected (%s)\n", (msg ? msg : "(null)")); +#endif + return; + } + + /* Ignore duplicate message on the same line. BTW, this is dubious. FIXME */ + if (!force_error && msg == prev_msg && prev_lineno == elc.line) + return; + + ctxp->java_error_flag = 0; + if (do_warning) + java_warning_count++; + else + java_error_count++; + + if (elc.col == 0 && msg[1] == ';') + { + elc.col = ctxp->p_line->char_col-1; + elc.line = ctxp->p_line->lineno; + } + + save_lineno = lineno; + prev_lineno = lineno = elc.line; + prev_msg = msg; + + code_from_source = java_get_line_col (ctxp->filename, elc.line, elc.col); + obstack_grow0 (&temporary_obstack, + code_from_source, strlen (code_from_source)); + remainder = obstack_finish (&temporary_obstack); + if (do_warning) + warning ("%s.\n%s", msg, remainder); + else + error ("%s.\n%s", msg, 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. */ + ctxp->prevent_ese = lineno = save_lineno; +} + +static void +parse_error (msg) + char *msg; +{ + java_error (NULL); + java_error (msg); +} + +/* Issue an error message at a current source line CL */ + +static void +parse_error_context VPROTO ((tree cl, char *msg, ...)) +{ +#ifndef __STDC__ + tree cl; + char *msg; +#endif + char buffer [4096]; + va_list ap; + + VA_START (ap, msg); +#ifndef __STDC__ + cl = va_arg (ap, tree); + msg = va_arg (ap, char *); +#endif + vsprintf (buffer, msg, ap); + + force_error = 1; + ctxp->elc.line = EXPR_WFL_LINENO (cl); + ctxp->elc.col = (EXPR_WFL_COLNO (cl) == 0xfff ? -1 : EXPR_WFL_COLNO (cl)); + + parse_error (buffer); + force_error = 0; +} + +/* Issue a warning at a current source line CL */ + +static void +parse_warning_context VPROTO ((tree cl, char *msg, ...)) +{ +#ifndef __STDC__ + tree cl; + char *msg; +#endif + char buffer [4096]; + va_list ap; + + VA_START (ap, msg); +#ifndef __STDC__ + cl = va_arg (ap, tree); + msg = va_arg (ap, char *); +#endif + vsprintf (buffer, msg, ap); + + force_error = do_warning = 1; + ctxp->elc.line = EXPR_WFL_LINENO (cl); + ctxp->elc.col = (EXPR_WFL_COLNO (cl) == 0xfff ? -1 : EXPR_WFL_COLNO (cl)); + + parse_error (buffer); + do_warning = force_error = 0; +} + +void +java_report_errors () +{ + if (java_error_count) + fprintf (stderr, "%d error%s", + java_error_count, (java_error_count == 1 ? "" : "s")); + if (java_warning_count) + fprintf (stderr, "%s%d warning%s", (java_error_count ? ", " : ""), + java_warning_count, (java_warning_count == 1 ? "" : "s")); + if (java_error_count || java_warning_count) + putc ('\n', stderr); +} + +static char * +java_accstring_lookup (flags) + int flags; +{ + static char buffer [80]; +#define COPY_RETURN(S) {strcpy (buffer, S); return buffer;} + + /* Access modifier looked-up first for easier report on forbidden + access. */ + if (flags & ACC_PUBLIC) COPY_RETURN ("public"); + if (flags & ACC_PRIVATE) COPY_RETURN ("private"); + if (flags & ACC_PROTECTED) COPY_RETURN ("protected"); + if (flags & ACC_STATIC) COPY_RETURN ("static"); + if (flags & ACC_FINAL) COPY_RETURN ("final"); + if (flags & ACC_SYNCHRONIZED) COPY_RETURN ("synchronized"); + if (flags & ACC_VOLATILE) COPY_RETURN ("volatile"); + if (flags & ACC_TRANSIENT) COPY_RETURN ("transient"); + if (flags & ACC_NATIVE) COPY_RETURN ("native"); + if (flags & ACC_INTERFACE) COPY_RETURN ("interface"); + if (flags & ACC_ABSTRACT) COPY_RETURN ("abstract"); + + buffer [0] = '\0'; + return buffer; +#undef COPY_RETURN +} + +static void +redefinition_error (context, id, decl, cl) + char *context; + tree id, decl, cl; +{ + parse_error_context (cl, "%s `%s' already defined in %s:%d", + context, IDENTIFIER_POINTER (id), + DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); + /* Here we should point out where its redefined. It's a unicode. FIXME */ +} + +/* Build something that the type identifier resolver will identify as + being an array to an unresolved type. TYPE_WFL is a WFL on a + identifier. */ + +static tree +build_unresolved_array_type (type_or_wfl) + tree type_or_wfl; +{ + char *ptr; + + /* TYPE_OR_WFL might be an array on a primitive type. In this case, + just create a array type */ + if (TREE_CODE (type_or_wfl) == RECORD_TYPE) + { + tree type = build_java_array_type (type_or_wfl, -1); + CLASS_LOADED_P (type) = CLASS_LOADED_P (type_or_wfl); + return type; + } + + obstack_1grow (&temporary_obstack, '['); + obstack_grow0 (&temporary_obstack, + IDENTIFIER_POINTER (EXPR_WFL_NODE (type_or_wfl)), + IDENTIFIER_LENGTH (EXPR_WFL_NODE (type_or_wfl))); + ptr = obstack_finish (&temporary_obstack); + return build_expr_wfl (get_identifier (ptr), + EXPR_WFL_FILENAME (type_or_wfl), + EXPR_WFL_LINENO (type_or_wfl), + EXPR_WFL_COLNO (type_or_wfl)); +} + +/* Check modifiers. If one doesn't fit, retrieve it in its declaration line + and point it out. */ + +static void +check_modifiers (message, value, mask) + char *message; + int value; + int mask; +{ + /* Should point out the one that don't fit. ASCII/unicode, + going backward. FIXME */ + if (value & ~mask) + { + int i, remainder = value & ~mask; + for (i = 0; i <= 10; i++) + if ((1 << i) & remainder) + parse_error_context (ctxp->modifier_ctx [i], message, + java_accstring_lookup (1 << i)); + } +} + +static void +parser_add_interface (class_decl, interface_decl, wfl) + tree class_decl, interface_decl, wfl; +{ + if (maybe_add_interface (TREE_TYPE (class_decl), TREE_TYPE (interface_decl))) + parse_error_context (wfl, "Interface `%s' repeated", + IDENTIFIER_POINTER (DECL_NAME (interface_decl))); +} + +/* Bulk of common class/interface checks. Return 1 if an error was + encountered. TAG is 0 for a class, 1 for an interface. */ + +static int +check_class_interface_creation (is_interface, flags, raw_name, qualified_name, decl, cl) + int is_interface, flags; + tree raw_name, qualified_name, decl, cl; +{ + tree node; + + if (!quiet_flag) + fprintf (stderr, " %s %s", (is_interface ? "interface" : "class"), + IDENTIFIER_POINTER (qualified_name)); + + /* Scope of an interface/class type name: + - Can't be imported by a single type import + - Can't already exists in the package */ + if (IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (raw_name) + && (node = find_name_in_single_imports (raw_name))) + { + parse_error_context + (cl, "%s name `%s' clashes with imported type `%s'", + (is_interface ? "Interface" : "Class"), + IDENTIFIER_POINTER (raw_name), IDENTIFIER_POINTER (node)); + return 1; + } + if (decl && CLASS_COMPLETE_P (decl)) + { + redefinition_error ((is_interface ? "Interface" : "Class"), + qualified_name, decl, cl); + return 1; + } + + /* If public, file name should match class/interface name */ + if (flags & ACC_PUBLIC) + { + char *f; + + /* Contains OS dependent assumption on path separator. FIXME */ + for (f = &input_filename [strlen (input_filename)]; + f != input_filename && f[0] != '/'; f--); + if (f[0] == '/') + f++; + if (strncmp (IDENTIFIER_POINTER (raw_name), + f , IDENTIFIER_LENGTH (raw_name)) || + f [IDENTIFIER_LENGTH (raw_name)] != '.') + parse_error_context (cl, "Public %s `%s' must be defined in a file " + "called `%s.java'", + (is_interface ? "interface" : "class"), + IDENTIFIER_POINTER (qualified_name), + IDENTIFIER_POINTER (raw_name)); + } + + check_modifiers ((is_interface ? + "Illegal modifier `%s' for interface declaration" : + "Illegal modifier `%s' for class declaration"), flags, + (is_interface ? INTERFACE_MODIFIERS : CLASS_MODIFIERS)); + return 0; +} + +/* If DECL is NULL, create and push a new DECL, record the current + line CL and do other maintenance things. */ + +static tree +maybe_create_class_interface_decl (decl, qualified_name, cl) + tree decl, qualified_name, cl; +{ + if (decl) + DECL_ARTIFICIAL (decl) = 1; /* FIXME */ + else + decl = push_class (make_class (), qualified_name); + + /* Take care of the file and line business */ + DECL_SOURCE_FILE (decl) = EXPR_WFL_FILENAME (cl); + DECL_SOURCE_LINE (decl) = EXPR_WFL_LINENO (cl); + CLASS_FROM_SOURCE_P (TREE_TYPE (decl)) = 1; + + ctxp->current_parsed_class = decl; + + /* Link the declaration to the already seen ones */ + TREE_CHAIN (decl) = ctxp->class_list; + ctxp->class_list = decl; + /* Install a new dependency list element */ + create_jdep_list (ctxp); + + SOURCE_FRONTEND_DEBUG (("Defining class/interface %s", + IDENTIFIER_POINTER (qualified_name))); + return decl; +} + +static void +add_superinterfaces (decl, interface_list) + tree decl, interface_list; +{ + tree node; + /* Superinterface(s): if present and defined, parser_check_super_interface () + takes care of ensuring that: + - This is an accessible interface type, + - Circularity detection. + parser_add_interface is then called. If present but not defined, + the check operation is delayed until the super interface gets + defined. */ + for (node = interface_list; node; node = TREE_CHAIN (node)) + { + tree current = TREE_PURPOSE (node), interface_decl; + if ((interface_decl = IDENTIFIER_CLASS_VALUE (EXPR_WFL_NODE (current)))) + { + if (!parser_check_super_interface (interface_decl, decl, current)) + parser_add_interface (decl, interface_decl, current); + } + else + register_incomplete_type (JDEP_INTERFACE, + current, decl, NULL_TREE); + } +} + +/* Create an interface in pass1 and return its decl. Return the + interface's decl in pass 2. */ + +static tree +create_interface (flags, id, super) + int flags; + tree id, super; +{ + int chk; + tree raw_name = EXPR_WFL_NODE (id); + tree q_name = parser_qualified_classname (id); + tree decl = IDENTIFIER_CLASS_VALUE (q_name); + + EXPR_WFL_NODE (id) = q_name; /* Keep source location, even if refined. */ + + /* Basic checks: scope, redefinition, modifiers */ + if (check_class_interface_creation (1, flags, raw_name, q_name, decl, id)) + return NULL_TREE; + + /* Interface modifiers check + - public/abstract allowed (already done at that point) + - abstract is obsolete (comes first, it's a warning, or should be) + - Can't use twice the same (checked in the modifier rule) */ + if (flags & ACC_ABSTRACT) + parse_warning_context + (MODIFIER_WFL (ABSTRACT_TK), + "Obsolete use of `abstract' modifier. Interface `%s' is implicitely " + "abstract", IDENTIFIER_POINTER (raw_name)); + if (flags & ACC_PUBLIC && flags & ACC_ABSTRACT) + parse_error_context + (MODIFIER_WFL (ABSTRACT_TK), + "Can't specify both `public' and `abstract' modifiers in the " + "definition of interface `%s'", IDENTIFIER_POINTER (raw_name)); + + /* Create a new decl if DECL is NULL, otherwise fix it */ + decl = maybe_create_class_interface_decl (decl, q_name, id); + + /* Set super info and mark the class a complete */ + set_super_info (ACC_ABSTRACT | ACC_INTERFACE | flags, TREE_TYPE (decl), + object_type_node, ctxp->interface_number); + ctxp->interface_number = 0; + CLASS_COMPLETE_P (decl) = 1; + add_superinterfaces (decl, super); + + return decl; +} + +/* Create an class in pass1 and return its decl. Return class + interface's decl in pass 2. */ + +static tree +create_class (flags, id, super, interfaces) + int flags; + tree id, super, interfaces; +{ + int chk; + tree raw_name = EXPR_WFL_NODE (id); + tree class_id, decl; + tree super_decl = NULL, super_decl_type; + + class_id = parser_qualified_classname (id); + decl = IDENTIFIER_CLASS_VALUE (class_id); + EXPR_WFL_NODE (id) = class_id; + + /* Basic check: scope, redefinition, modifiers */ + if (check_class_interface_creation (0, flags, raw_name, class_id, decl, id)) + return NULL_TREE; + + /* Class modifier check: + - Allowed modifier (already done at that point) + - abstract AND final forbidden + - Public classes defined in the correct file */ + if ((flags & ACC_ABSTRACT) && (flags & ACC_FINAL)) + parse_error_context (id, "Class `%s' can't be declared both abstract " + "and final", IDENTIFIER_POINTER (raw_name)); + + /* Create a new decl if DECL is NULL, otherwise fix it */ + decl = maybe_create_class_interface_decl (decl, class_id, id); + + /* If SUPER exists, use it, otherwise use Object */ + if (super) + { + /* Can't extend java.lang.Object */ + if (TREE_TYPE (IDENTIFIER_CLASS_VALUE (class_id)) == object_type_node) + { + parse_error_context (id, "Can't extend `java.lang.Object'"); + return NULL_TREE; + } + + /* The class is known and exists if there is a decl. Otherwise, + postpone the operation and do it later. */ + super_decl = IDENTIFIER_CLASS_VALUE (EXPR_WFL_NODE (super)); + if (super_decl) + { + parser_check_super (super_decl, decl, id); + super_decl_type = TREE_TYPE (super_decl); + } + else + super_decl_type = + register_incomplete_type (JDEP_SUPER, super, decl, NULL_TREE); + } + else if (TREE_TYPE (decl) != object_type_node) + super_decl_type = object_type_node; + /* We're defining java.lang.Object */ + else + super_decl_type = NULL_TREE; + + /* Set super info and mark the class a complete */ + set_super_info (flags, TREE_TYPE (decl), super_decl_type, + ctxp->interface_number); + ctxp->interface_number = 0; + CLASS_COMPLETE_P (decl) = 1; + add_superinterfaces (decl, interfaces); + + return decl; +} + +/* Can't use lookup_field () since we don't want to load the class and + can't set the CLASS_LOADED_P flag */ + +static tree +find_field (class, name) + tree class; + tree name; +{ + tree decl; + for (decl = TYPE_FIELDS (class); decl; decl = TREE_CHAIN (decl)) + { + if (DECL_NAME (decl) == name) + return decl; + } + return NULL_TREE; +} + +/* Wrap around lookup_field that doesn't potentially upset the value + of CLASS */ + +static tree +lookup_field_wrapper (class, name) + tree class, name; +{ + tree type = class; + return lookup_field (&type, name); +} + +/* Find duplicate field within the same class declarations and report + the error */ + +static int +duplicate_declaration_error (class, new_field_name, new_type, cl) + tree class, new_field_name, new_type, cl; +{ + /* This might be modified to work with method decl as well */ + tree decl = find_field (TREE_TYPE (ctxp->current_parsed_class), + new_field_name); + if (decl) + { + char *t1 = strdup ((char *)lang_printable_name (new_type, 1)); + char *t2 = + strdup ((TREE_CODE (TREE_TYPE (decl)) == TREE_LIST ? + IDENTIFIER_POINTER (TYPE_NAME + (TREE_PURPOSE (TREE_TYPE (decl)))) : + (char *)lang_printable_name (TREE_TYPE (decl), 1))); + parse_error_context + (cl , "Duplicate variable declaration: `%s %s' was `%s %s' (%s:%d)", + t1, IDENTIFIER_POINTER (new_field_name), + t2, IDENTIFIER_POINTER (DECL_NAME (decl)), + DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); + free (t1); + free (t2); + return 0; + } + return 1; +} + +/* Field registration routine. If TYPE doesn't exist, field + declarations are linked to the undefined TYPE dependency list, to + be later resolved in java_complete_class () */ + +static void +register_fields (flags, type, variable_list) + int flags; + tree type, variable_list; +{ + tree current, type_decl, returned_type; + tree class_type = TREE_TYPE (ctxp->current_parsed_class); + int saved_lineno = lineno; + int must_chain = 0; + tree wfl = NULL_TREE; + + /* If we're adding fields to interfaces, those fields are public, + static, final */ + if (CLASS_INTERFACE (TYPE_NAME (class_type))) + { + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (PUBLIC_TK), + flags, ACC_PUBLIC, + "%s", "interface field(s)"); + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (STATIC_TK), + flags, ACC_STATIC, + "%s", "interface field(s)"); + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (FINAL_TK), + flags, ACC_FINAL, "%s", "interface field(s)"); + check_modifiers ("Illegal interface member modifier `%s'", flags, + INTERFACE_FIELD_MODIFIERS); + flags |= (ACC_PUBLIC | ACC_STATIC | ACC_FINAL); + } + + if (unresolved_type_p (type, &returned_type)) + { + if (returned_type) + type = returned_type; + else + { + wfl = type; + type = obtain_incomplete_type (type); + must_chain = 1; + } + } + + for (current = variable_list; current; current = TREE_CHAIN (current)) + { + tree cl = TREE_PURPOSE (current); + tree init = TREE_VALUE (current); + tree current_name = EXPR_WFL_NODE (cl); + + if (duplicate_declaration_error (class_type, current_name, type, cl)) + { + tree field_decl; + lineno = EXPR_WFL_LINENO (cl); + field_decl = add_field (class_type, current_name, type, flags); + + /* Check if we must chain. */ + if (must_chain) + register_incomplete_type (JDEP_FIELD, wfl, field_decl, type); + + /* Default value of a static field is 0 and it is considered + initialized. */ + if (flags & ACC_STATIC) + INITIALIZED_P (field_decl) = 1; + + /* If we have an initialization value tied to the field */ + if (init) + { + /* The field is declared static */ + if (flags & ACC_STATIC) + { + /* FIXME */ + if (flags & ACC_FINAL) + ; + /* Otherwise, the field should be initialized in + . This field is remembered so we can + generate later. */ + else + { + INITIALIZED_P (field_decl) = 1; + TREE_CHAIN (init) = ctxp->static_initialized; + ctxp->static_initialized = init; + } + } + /* A non-static field declared with an immediate + initialization is to be initialized in , if + any. This field is remembered to be processed at the + time of the generation of . */ + else + { + TREE_CHAIN (init) = ctxp->non_static_initialized; + ctxp->non_static_initialized = init; + } + } + } + } + lineno = saved_lineno; +} + +/* Check whether it is necessary to generate a for the class + we just parsed. */ + +static void +maybe_generate_clinit () +{ + int saved_lineno; + tree meth, mdecl, c; + tree cclass, class_wfl; + + if (!ctxp->static_initialized || java_error_count) + return; + + cclass = TREE_TYPE (ctxp->current_parsed_class); + class_wfl = build_expr_wfl (DECL_NAME (TYPE_NAME (cclass)), + input_filename, 0, 0); + + saved_lineno = lineno; + lineno = 0; + meth = make_node (FUNCTION_TYPE); + TREE_TYPE (meth) = void_type_node; + TYPE_ARG_TYPES (meth) = NULL_TREE; + mdecl = add_method (cclass, ACC_STATIC, clinit_identifier_node, + build_java_signature (meth)); + lineno = saved_lineno; + + DECL_SOURCE_LINE (mdecl) = 1; + DECL_SOURCE_LINE_MERGE (mdecl, 1); + source_start_java_method (mdecl); + enter_block (); + + /* Keep initialization in order to enforce 8.5 */ + ctxp->static_initialized = nreverse (ctxp->static_initialized); + + /* We process the list of assignment we produced as the result of + the declaration of initialized static field and add them as + statement to the method. */ + for (c = ctxp->static_initialized; c; c = TREE_CHAIN (c)) + { + /* We build the assignment expression that will initialize the + field to its value. There are strict rules on static + initializers (8.5). FIXME */ + java_method_add_stmt (mdecl, c); + } + + BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = exit_block (); + exit_block (); + ctxp->static_initialized = NULL_TREE; +} + +/* Shared accros method_declarator and method_header to remember the + patch stage that was reached during the declaration of the method. + A method DECL is built differently is there is no patch + (JDEP_NO_PATCH) or a patch (JDEP_METHOD or JDEP_METHOD_RETURN) + pending on the currently defined method. */ + +static int patch_stage; + +/* Check the method declaration and add the method to its current + class. If the argument list is known to contain incomplete types, + the method is partially added and the registration will be resume + once the method arguments resolved */ + +static tree +method_header (flags, type, mdecl, throws) + int flags; + tree type, mdecl, throws; +{ + tree meth = TREE_VALUE (mdecl); + tree id = TREE_PURPOSE (mdecl); + tree this_class = TREE_TYPE (ctxp->current_parsed_class); + tree handle_class = CLASS_TO_HANDLE_TYPE (this_class); + tree meth_name, returned_type; + int saved_lineno; + + check_modifiers_consistency (flags); + + /* There are some forbidden modifiers for an abstract method and its + class must be abstract as well. */ + if (flags & ACC_ABSTRACT) + { + ABSTRACT_CHECK (flags, ACC_PRIVATE, id, "Private"); + ABSTRACT_CHECK (flags, ACC_STATIC, id, "Static"); + ABSTRACT_CHECK (flags, ACC_FINAL, id, "Final"); + ABSTRACT_CHECK (flags, ACC_NATIVE, id, "Native"); + ABSTRACT_CHECK (flags, ACC_SYNCHRONIZED,id, "Synchronized"); + if (!CLASS_ABSTRACT (TYPE_NAME (this_class))) + parse_error_context + (id, "Class `%s' must be declared abstract to define abstract " + "method `%s'", + IDENTIFIER_POINTER (DECL_NAME (ctxp->current_parsed_class)), + IDENTIFIER_POINTER (EXPR_WFL_NODE (id))); + } + + + /* Method declared within the scope of an interface are implicitly + abstract and public. Conflicts with other erroneously provided + modifiers are check right after. */ + + if (CLASS_INTERFACE (TYPE_NAME (this_class))) + { + /* If FLAGS isn't set because of a modifier, turn the + corresponding modifier WFL to NULL so we issue a warning on + the obsolete use of the modifier */ + if (!(flags & ACC_PUBLIC)) + MODIFIER_WFL (PUBLIC_TK) = NULL; + if (!(flags & ACC_ABSTRACT)) + MODIFIER_WFL (ABSTRACT_TK) = NULL; + flags |= ACC_PUBLIC; + flags |= ACC_ABSTRACT; + } + + /* Modifiers context reset moved up, so abstract method declaration + modifiers can be later checked. */ + + meth_name = EXPR_WFL_NODE (id); + + if (unresolved_type_p (type, &returned_type)) + { + if (returned_type) + TREE_TYPE (meth) = returned_type; + else + { + patch_stage = JDEP_METHOD_RETURN; + TREE_TYPE (meth) = + register_incomplete_type (patch_stage, type, id, NULL_TREE); + } + } + else + TREE_TYPE (meth) = type; + + saved_lineno = lineno; + /* When defining an abstract or interface method, the curly + bracket at level 1 doesn't exist because there is no function + body */ + lineno = (ctxp->first_ccb_indent1 ? ctxp->first_ccb_indent1 : + EXPR_WFL_LINENO (id)); + + if (patch_stage) /* includes ret type and/or all args */ + { + jdep *jdep; + meth = add_method_1 (this_class, flags, meth_name, meth); + /* Patch for the return type */ + if (patch_stage == JDEP_METHOD_RETURN) + { + jdep = CLASSD_LAST (ctxp->classd_list); + JDEP_GET_PATCH (jdep) = &TREE_TYPE (TREE_TYPE (meth)); + } + /* This is the stop JDEP. METH allows the function's signature + to be computed. */ + register_incomplete_type (JDEP_METHOD_END, NULL_TREE, meth, NULL_TREE); + } + else + { + tree signature = build_java_signature (meth); + tree arg, orig_arg; + /* Save original argument list, including argument's names */ + orig_arg = TYPE_ARG_TYPES (meth); + /* Add the method to its class */ + meth = add_method (this_class, flags, meth_name, signature); + /* Fix the method argument list so we have the argument name + information */ + arg = TYPE_ARG_TYPES (TREE_TYPE (meth)); + if (TREE_CODE (TREE_TYPE (meth)) == METHOD_TYPE) + { + TREE_PURPOSE (arg) = this_identifier_node; + arg = TREE_CHAIN (arg); + } + while (orig_arg) + { + TREE_PURPOSE (arg) = TREE_PURPOSE (orig_arg); + orig_arg = TREE_CHAIN (orig_arg); + arg = TREE_CHAIN (arg); + } + } + DECL_MAX_LOCALS (meth) = ctxp->formal_parameter_number+1; + lineno = saved_lineno; + /* We set the DECL_NAME to ID so we can track the location where + the function was declared. This allow us to report + redefinition error accurately. When method are verified, + DECL_NAME is reinstalled properly (using the content of the + WFL node ID) (see check_method_redefinition). We don't do that + when Object is being defined. */ + if (TREE_TYPE (ctxp->current_parsed_class) != object_type_node) + DECL_NAME (meth) = id; + return meth; +} + +/* Check modifiers that can be declared but exclusively */ + +static void +check_modifiers_consistency (flags) + int flags; +{ + int acc_count = 0; + tree cl = NULL_TREE; + + THIS_MODIFIER_ONLY (flags, ACC_PUBLIC, 0, acc_count, cl); + THIS_MODIFIER_ONLY (flags, ACC_PRIVATE, 1, acc_count, cl); + THIS_MODIFIER_ONLY (flags, ACC_PROTECTED, 2, acc_count, cl); + if (acc_count > 1) + parse_error_context + (cl, "Inconsistent member declaration. At most one of `public', " + "`private', or `protected' may be specified"); +} + +/* Check the methode header METH for abstract specifics features */ + +static void +check_abstract_method_header (meth) + tree meth; +{ + int flags = get_access_flags_from_decl (meth); + /* DECL_NAME might still be a WFL node */ + tree name = (TREE_CODE (DECL_NAME (meth)) == EXPR_WITH_FILE_LOCATION ? + EXPR_WFL_NODE (DECL_NAME (meth)) : DECL_NAME (meth)); + + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (ABSTRACT_TK), flags, + ACC_ABSTRACT, "abstract method `%s'", + IDENTIFIER_POINTER (name)); + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (PUBLIC_TK), flags, + ACC_PUBLIC, "abstract method `%s'", + IDENTIFIER_POINTER (name)); + + check_modifiers ("Illegal modifier `%s' for interface method", + flags, INTERFACE_METHOD_MODIFIERS); +} + +/* Create a FUNCTION_TYPE node and start augmenting it with the + declared function arguments. Arguments type that can't be resolved + are left as they are, but the returned node is marked as containing + incomplete types. */ + +static tree +method_declarator (id, list) + tree id, list; +{ + tree arg_types = NULL_TREE, current, node; + tree meth = make_node (FUNCTION_TYPE); + jdep *jdep; + int incomplete = 0; + + patch_stage = JDEP_NO_PATCH; + + for (current = list; current; current = TREE_CHAIN (current)) + { + tree wfl_name = TREE_PURPOSE (current); + tree type = TREE_VALUE (current); + tree name = EXPR_WFL_NODE (wfl_name); + tree patchable_type = NULL_TREE, already; + tree arg_node, returned_type; + + /* Check redefinition */ + for (already = arg_types; already; already = TREE_CHAIN (already)) + if (TREE_PURPOSE (already) == name) + { + parse_error_context + (wfl_name, "Variable `%s' is used more than once in the " + "argument list of method `%s'", IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (EXPR_WFL_NODE (id))); + break; + } + + /* If we've an incomplete argument type, we know there is a location + to patch when the type get resolved, later. */ + jdep = NULL; + if (unresolved_type_p (type, &returned_type)) + { + if (returned_type) + type = returned_type; + else + { + patch_stage = JDEP_METHOD; + type = register_incomplete_type (patch_stage, type, + wfl_name, NULL_TREE); + jdep = CLASSD_LAST (ctxp->classd_list); + JDEP_MISC (jdep) = id; + } + } + /* The argument node: a name and a (possibly) incomplete type */ + arg_node = build_tree_list (name, type); + if (jdep) + JDEP_GET_PATCH (jdep) = &TREE_VALUE (arg_node); + TREE_CHAIN (arg_node) = arg_types; + arg_types = arg_node; + } + TYPE_ARG_TYPES (meth) = nreverse (arg_types); + node = build_tree_list (id, meth); + return node; +} + +static int +unresolved_type_p (wfl, returned) + tree wfl; + tree *returned; + +{ + if (TREE_CODE (wfl) == EXPR_WITH_FILE_LOCATION) + { + tree decl = IDENTIFIER_CLASS_VALUE (EXPR_WFL_NODE (wfl)); + if (returned) + *returned = (decl ? TREE_TYPE (decl) : NULL_TREE); + return 1; + } + if (returned) + *returned = wfl; + return 0; +} + +/* From NAME, build a qualified identifier node using the + qualification from the current package definition. */ + +static tree +parser_qualified_classname (name) + tree name; +{ + if (ctxp->package) + return merge_qualified_name (ctxp->package, EXPR_WFL_NODE (name)); + else + return EXPR_WFL_NODE (name); +} + +/* Called once the type a interface extends is resolved. Returns 0 if + everything is OK. */ + +static int +parser_check_super_interface (super_decl, this_decl, this_wfl) + tree super_decl, this_decl, this_wfl; +{ + tree super_type = TREE_TYPE (super_decl); + + /* Has to be an interface */ + if (!CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (super_decl)))) + { + parse_error_context + (this_wfl, "Can't use %s `%s' to implement/extend %s `%s'", + (TYPE_ARRAY_P (super_type) ? "array" : "class"), + IDENTIFIER_POINTER (DECL_NAME (super_decl)), + (CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (this_decl))) ? + "interface" : "class"), + IDENTIFIER_POINTER (DECL_NAME (this_decl))); + return 1; + } + + /* Check scope: same package OK, other package: OK if public */ + if (check_pkg_class_access (DECL_NAME (super_decl), lookup_cl (this_decl))) + return 1; + + SOURCE_FRONTEND_DEBUG (("Completing interface %s with %s", + IDENTIFIER_POINTER (DECL_NAME (this_decl)), + IDENTIFIER_POINTER (DECL_NAME (super_decl)))); + return 0; +} + +/* Makes sure that SUPER_DECL is suitable to extend THIS_DECL. Returns + 0 if everthing is OK. */ + +static int +parser_check_super (super_decl, this_decl, wfl) + tree super_decl, this_decl, wfl; +{ + tree this_type = TREE_TYPE (this_decl); + tree super_type = TREE_TYPE (super_decl); + + /* SUPER should be a CLASS (neither an array nor an interface) */ + if (TYPE_ARRAY_P (super_type) || CLASS_INTERFACE (TYPE_NAME (super_type))) + { + parse_error_context + (wfl, "Class `%s' can't subclass %s `%s'", + IDENTIFIER_POINTER (DECL_NAME (this_decl)), + (CLASS_INTERFACE (TYPE_NAME (super_type)) ? "interface" : "array"), + IDENTIFIER_POINTER (DECL_NAME (super_decl))); + return 1; + } + + if (CLASS_FINAL (TYPE_NAME (super_type))) + { + parse_error_context (wfl, "Can't subclass final classes: %s", + IDENTIFIER_POINTER (DECL_NAME (super_decl))); + return 1; + } + + /* Check scope: same package OK, other package: OK if public */ + if (check_pkg_class_access (DECL_NAME (super_decl), wfl)) + return 1; + + SOURCE_FRONTEND_DEBUG (("Completing class %s with %s", + IDENTIFIER_POINTER (DECL_NAME (this_decl)), + IDENTIFIER_POINTER (DECL_NAME (super_decl)))); + return 0; +} + +/* Create a new dependency list and link it (in a LIFO manner) to the + CTXP list of type dependency list. */ + +static void +create_jdep_list (ctxp) + struct parser_ctxt *ctxp; +{ + jdeplist *new = malloc (sizeof (jdeplist)); + + if (!new) + fatal ("Can't alloc jdeplist - create_jdep_list"); + + new->first = new->last = NULL; + new->next = ctxp->classd_list; + ctxp->classd_list = new; +} + +static jdeplist * +reverse_jdep_list (ctxp) + struct parser_ctxt *ctxp; +{ + register jdeplist *prev = NULL, *current, *next; + for (current = ctxp->classd_list; current; current = next) + { + next = current->next; + current->next = prev; + prev = current; + } + return prev; +} + +/* Create a fake pointer based on the ID stored in the WFL */ + +static tree +obtain_incomplete_type (wfl) + tree wfl; +{ + tree ptr; + tree name = EXPR_WFL_NODE (wfl); + + for (ptr = ctxp->incomplete_class; ptr; ptr = TREE_CHAIN (ptr)) + if (TYPE_NAME (TREE_PURPOSE (ptr)) == name) + break; + + if (!ptr) + { + tree core; + push_obstacks (&permanent_obstack, &permanent_obstack); + BUILD_PTR_FROM_NAME (core, name); + ptr = build_tree_list (core, NULL_TREE); + pop_obstacks (); + TREE_CHAIN (ptr) = ctxp->incomplete_class; + ctxp->incomplete_class = ptr; + } + + return ptr; +} + +/* Register a incomplete type whose name is WFL. Reuse PTR if PTR is + non NULL instead of computing a new fake type based on WFL. The new + dependency is inserted in the current type dependency list, in FIFO + manner. */ + +static tree +register_incomplete_type (kind, wfl, decl, ptr) + int kind; + tree wfl, decl, ptr; +{ + jdep *new = malloc (sizeof (jdep)); + + if (!new) + fatal ("Can't allocate new jdep - register_incomplete_type"); + if (!ptr && kind != JDEP_METHOD_END) /* JDEP_METHOD_END is a mere marker */ + ptr = obtain_incomplete_type (wfl); + + JDEP_KIND (new) = kind; + JDEP_DECL (new) = decl; + JDEP_SOLV (new) = ptr; + JDEP_WFL (new) = wfl; + JDEP_CHAIN (new) = NULL; + JDEP_MISC (new) = NULL_TREE; + JDEP_GET_PATCH (new) = (tree *)NULL; + + JDEP_INSERT (ctxp->classd_list, new); + + return ptr; +} + +void +java_check_circular_reference () +{ + tree current; + for (current = ctxp->class_list; current; current = TREE_CHAIN (current)) + { + tree type = TREE_TYPE (current); + if (CLASS_INTERFACE (TYPE_NAME (type))) + { + /* Check all interfaces this class extends */ + tree basetype_vec = TYPE_BINFO_BASETYPES (type); + int n, i; + + if (!basetype_vec) + return; + n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; i < n; i++) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + if (vec_elt && BINFO_TYPE (vec_elt) != object_type_node + && interface_of_p (type, BINFO_TYPE (vec_elt))) + parse_error_context (lookup_cl (current), + "Cyclic interface inheritance"); + } + } + else + if (inherits_from_p (CLASSTYPE_SUPER (type), type)) + parse_error_context (lookup_cl (current), + "Cyclic class inheritance"); + } +} + +void +safe_layout_class (class) + tree class; +{ + tree save_current_class = current_class; + char *save_input_filename = input_filename; + int save_lineno = lineno; + + push_obstacks (&permanent_obstack, &permanent_obstack); + layout_class (class); + pop_obstacks (); + + current_class = save_current_class; + input_filename = save_input_filename; + lineno = save_lineno; + CLASS_LOADED_P (class) = 1; +} + +static tree +jdep_resolve_class (dep) + jdep *dep; +{ + tree decl; + + if (!JDEP_RESOLVED_P (dep)) + { + decl = + resolve_class (JDEP_TO_RESOLVE (dep), JDEP_DECL (dep), JDEP_WFL (dep)); + JDEP_RESOLVED (dep, decl); + } + else + decl = JDEP_RESOLVED_DECL (dep); + + if (!decl) + { + complete_class_report_errors (dep); + return NULL_TREE; + } + return decl; +} + +/* Complete unsatisfied class declaration and their dependencies */ + +void +java_complete_class () +{ + tree current; + tree cclass; + jdeplist *cclassd; + int error_found; + + push_obstacks (&permanent_obstack, &permanent_obstack); + + /* Process imports and reverse the import on demand list */ + process_imports (); + if (ctxp->import_demand_list) + ctxp->import_demand_list = nreverse (ctxp->import_demand_list); + + /* Rever things so we have the right order */ + ctxp->class_list = nreverse (ctxp->class_list); + ctxp->classd_list = reverse_jdep_list (ctxp); + + for (cclassd = ctxp->classd_list, cclass = ctxp->class_list; + cclass && cclassd; + cclass = TREE_CHAIN (cclass), cclassd = CLASSD_CHAIN (cclassd)) + { + jdep *dep; + for (dep = CLASSD_FIRST (cclassd); dep; dep = JDEP_CHAIN (dep)) + { + tree decl; + + if (!(decl = jdep_resolve_class (dep))) + continue; + + /* Now it's time to patch */ + switch (JDEP_KIND (dep)) + { + case JDEP_SUPER: + /* Simply patch super */ + if (parser_check_super (decl, JDEP_DECL (dep), JDEP_WFL (dep))) + continue; + BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO + (TREE_TYPE (JDEP_DECL (dep)))), 0)) = TREE_TYPE (decl); + break; + + case JDEP_FIELD: + { + /* We do part of the job done in add_field */ + tree field_decl = JDEP_DECL (dep); + tree field_type = TREE_TYPE (decl); + push_obstacks (&permanent_obstack, &permanent_obstack); +#if ! JAVA_PROMOTE_TO_INT + if (TREE_CODE (field_type) == RECORD_TYPE) +#endif + field_type = promote_type (field_type); + pop_obstacks (); + TREE_TYPE (field_decl) = field_type; + SOURCE_FRONTEND_DEBUG + (("Completed field/var decl `%s' with `%s'", + IDENTIFIER_POINTER (DECL_NAME (field_decl)), + IDENTIFIER_POINTER (DECL_NAME (decl)))); + break; + } + case JDEP_METHOD: /* We start patching a method */ + case JDEP_METHOD_RETURN: + error_found = 0; + while (1) + { + if (decl) + { + tree type = promote_type (TREE_TYPE(decl)); + JDEP_APPLY_PATCH (dep, type); + SOURCE_FRONTEND_DEBUG + (((JDEP_KIND (dep) == JDEP_METHOD_RETURN ? + "Completing fct `%s' with ret type `%s'": + "Completing arg `%s' with type `%s'"), + IDENTIFIER_POINTER (EXPR_WFL_NODE + (JDEP_DECL_WFL (dep))), + IDENTIFIER_POINTER (DECL_NAME (decl)))); + } + else + error_found = 1; + dep = JDEP_CHAIN (dep); + if (JDEP_KIND (dep) == JDEP_METHOD_END) + break; + else + decl = jdep_resolve_class (dep); + } + if (!error_found) + { + tree mdecl = JDEP_DECL (dep), signature; + push_obstacks (&permanent_obstack, &permanent_obstack); + /* Recompute and reset the signature */ + signature = build_java_signature (TREE_TYPE (mdecl)); + set_java_signature (TREE_TYPE (mdecl), signature); + pop_obstacks (); + } + else + continue; + break; + + case JDEP_INTERFACE: + if (parser_check_super_interface (decl, JDEP_DECL (dep), + JDEP_WFL (dep))) + continue; + parser_add_interface (JDEP_DECL (dep), decl, JDEP_WFL (dep)); + break; + + case JDEP_VARIABLE: + JDEP_APPLY_PATCH (dep, promote_type (TREE_TYPE (decl))); + SOURCE_FRONTEND_DEBUG + (("Completing variable `%s' with type `%s'", + (TREE_CODE (JDEP_DECL_WFL (dep)) == EXPR_WITH_FILE_LOCATION ? + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep))) : + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL_WFL (dep)))), + IDENTIFIER_POINTER (DECL_NAME (decl)))); + break; + + case JDEP_TYPE: + JDEP_APPLY_PATCH (dep, TREE_TYPE (decl)); + SOURCE_FRONTEND_DEBUG + (("Completing a random type dependency on a '%s' node", + tree_code_name [TREE_CODE (JDEP_DECL (dep))])); + break; + + case JDEP_PARM: + JDEP_APPLY_PATCH (dep, promote_type (TREE_TYPE (decl))); + SOURCE_FRONTEND_DEBUG + (("Completing parameter `%s' with type `%s'", + IDENTIFIER_POINTER (JDEP_MISC (dep)), + IDENTIFIER_POINTER (DECL_NAME (decl)))); + break; + + default: + fatal ("incomplete switch - java_complete_class"); + } + } + } + pop_obstacks (); + return; +} + +/* Resolve class CLASS_TYPE. Handle the case of trying to resolve an + array. */ + +static tree +resolve_class (class_type, decl, cl) + tree class_type, decl, cl; +{ + char *name = IDENTIFIER_POINTER (TYPE_NAME (class_type)); + char *base = name; + tree resolved_type, resolved_type_decl; + + /* 1- Check to see if we have an array. If true, find what we really + want to resolve */ + while (name[0] == '[') + name++; + if (base != name) + TYPE_NAME (class_type) = get_identifier (name); + + /* 2- Resolve the bare type */ + if (!(resolved_type_decl = do_resolve_class (class_type, decl, cl))) + return NULL_TREE; + resolved_type = TREE_TYPE (resolved_type_decl); + + /* 3- If we have and array, reconstruct the array down to its nesting */ + if (base != name) + { + while (base != name) + { + if (TREE_CODE (resolved_type) == RECORD_TYPE) + resolved_type = promote_type (resolved_type); + resolved_type = build_java_array_type (resolved_type, -1); + name--; + } + /* Build a fake decl for this, since this is what is expected to + be returned. */ + resolved_type_decl = + build_decl (TYPE_DECL, TYPE_NAME (resolved_type), resolved_type); + /* Figure how those two things are important for error report. FIXME */ + DECL_SOURCE_LINE (resolved_type_decl) = 0; + DECL_SOURCE_FILE (resolved_type_decl) = input_filename; + } + return resolved_type_decl; +} + +/* Effectively perform the resolution of class CLASS_TYPE. DECL or CL + are used to report error messages. */ + +static tree +do_resolve_class (class_type, decl, cl) + tree class_type; + tree decl; + tree cl; +{ + tree new_class_decl; + tree original_name = NULL_TREE; + + /* Do not try to replace TYPE_NAME (class_type) by a variable, since + its is changed by find_in_imports{_on_demand} */ + + /* 1- Check for the type in single imports */ + if (find_in_imports (class_type)) + return NULL_TREE; + + /* 2- And check for the type in the current compilation unit. If it fails, + try with a name qualified with the package name if appropriate. */ + + if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)))) + { + if (!CLASS_LOADED_P (TREE_TYPE (new_class_decl)) && + !CLASS_FROM_SOURCE_P (TREE_TYPE (new_class_decl))) + load_class (TYPE_NAME (class_type), 0); + return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)); + } + + original_name = TYPE_NAME (class_type); + if (!QUALIFIED_P (TYPE_NAME (class_type)) && ctxp->package) + TYPE_NAME (class_type) = merge_qualified_name (ctxp->package, + TYPE_NAME (class_type)); + if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)))) + { + if (!CLASS_LOADED_P (TREE_TYPE (new_class_decl)) && + !CLASS_FROM_SOURCE_P (TREE_TYPE (new_class_decl))) + load_class (TYPE_NAME (class_type), 0); + return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)); + } + TYPE_NAME (class_type) = original_name; + + /* 3- Check an other compilation unit that bears the name of type */ + load_class (TYPE_NAME (class_type), 0); + if (check_pkg_class_access (TYPE_NAME (class_type), + (cl ? cl : lookup_cl (decl)))) + return NULL_TREE; + + if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)))) + return new_class_decl; + + /* 4- Check the import on demands. Don't allow bar.baz to be + imported from foo.* */ + if (!QUALIFIED_P (TYPE_NAME (class_type))) + if (find_in_imports_on_demand (class_type)) + return NULL_TREE; + + /* 5- Last call for a resolution */ + return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)); +} + +/* Resolve NAME and lay it out (if not done and if not the current + parsed class). Return a decl node. */ + +static tree +resolve_and_layout (name, cl) + tree name; + tree cl; +{ + tree decl = resolve_no_layout (name, cl); + if (decl && TREE_TYPE (decl) != current_class + && !CLASS_LOADED_P (TREE_TYPE (decl))) + safe_layout_class (TREE_TYPE (decl)); + return decl; +} + +/* Resolve a class, returns its decl but doesn't perform any + layout. The current parsing context is saved and restored */ + +static tree +resolve_no_layout (name, cl) + tree name, cl; +{ + tree ptr, decl; + BUILD_PTR_FROM_NAME (ptr, name); + java_parser_context_save_global (); + decl = resolve_class (ptr, NULL_TREE, cl); + java_parser_context_restore_global (); + + return decl; +} + +/* Called to report errors. Skip leader '[' in a complex array type + description that failed to be resolved. */ + +static char * +purify_type_name (name) + char *name; +{ + while (*name && *name == '[') + name++; + return name; +} + +/* The type CURRENT refers to can't be found. We print error messages. */ + +static void +complete_class_report_errors (dep) + jdep *dep; +{ + switch (JDEP_KIND (dep)) + { + case JDEP_SUPER: + parse_error_context + (JDEP_WFL (dep), "Superclass `%s' of class `%s' not found", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); + break; + case JDEP_FIELD: + parse_error_context + (JDEP_WFL (dep), "Type `%s' not found in declaration of field `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); + break; + case JDEP_METHOD: /* Covers arguments */ + parse_error_context + (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " + "argument `%s' of method `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep))), + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_MISC (dep)))); + break; + case JDEP_METHOD_RETURN: /* Covers return type */ + parse_error_context + (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " + "return type of method `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep)))); + break; + case JDEP_INTERFACE: + parse_error_context + (JDEP_WFL (dep), "Superinterface `%s' of %s `%s' not found", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + (CLASS_OR_INTERFACE (JDEP_DECL (dep), "class", "interface")), + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); + break; + case JDEP_VARIABLE: + parse_error_context + (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " + "local variable `%s'", + purify_type_name (IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep)))), + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); + break; + } +} + +/* Check uninitialized final. */ + +void +java_check_final () +{ +} + +static int +check_method_redefinition (class, method) + tree class, method; +{ + tree redef, name; + tree cl = DECL_NAME (method); + tree sig = TYPE_LANG_SPECIFIC (TREE_TYPE (method))->signature; + /* decl name of generated doesn't need to be fixed and + checked */ + if (DECL_NAME (method) != clinit_identifier_node) + { + /* NAME is just the plain name when Object is being defined */ + if (class != object_type_node) + name = DECL_NAME (method) = EXPR_WFL_NODE (DECL_NAME (method)); + else + name = DECL_NAME (method); + } + else + return 0; + + for (redef = TYPE_METHODS (class); redef; redef = TREE_CHAIN (redef)) + { + struct lang_type *t = TYPE_LANG_SPECIFIC (TREE_TYPE (redef)); + + if (! t || (redef == method)) + break; + if (DECL_NAME (redef) == name && sig == t->signature) + { + parse_error_context (cl, "Duplicate method declaration"); + return 1; + } + } + return 0; +} + +/* Check all the methods of CLASS. Methods are first completed then + checked according to regular method existance rules. + If no constructor were encountered, then build its declaration. */ + +static void +java_check_regular_methods (class_decl) + tree class_decl; +{ + tree method; + tree class = CLASS_TO_HANDLE_TYPE (TREE_TYPE (class_decl)); + tree super_class = CLASSTYPE_SUPER (class); + int seen_constructor = 0; + + TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); + + /* Should take interfaces into account. FIXME */ + for (method = TYPE_METHODS (class); method; method = TREE_CHAIN (method)) + { + tree found, sig; + tree method_wfl = DECL_NAME (method); + int aflags; + + if (DECL_CONSTRUCTOR_P (method)) + seen_constructor = 1; + + /* Check for redefinitions */ + if (check_method_redefinition (class, method)) + continue; + + sig = build_java_argument_signature (TREE_TYPE (method)); + + found = lookup_argument_method (super_class, DECL_NAME (method), sig); + if (! found) + continue; + /* Can't override a method with the same name and different return + types. */ + if (TREE_TYPE (TREE_TYPE (found)) != TREE_TYPE (TREE_TYPE (method))) + parse_warning_context + (method_wfl, + "Method `%s' redefined with different return type in class `%s'", + lang_printable_name (found), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + + /* Can't override final. Can't override static. */ + if (METHOD_FINAL (found) || METHOD_STATIC (found)) + { + /* Static *can* override static */ + if (METHOD_STATIC (found) && METHOD_STATIC (method)) + continue; + parse_error_context + (method_wfl, + "%s methods can't be overriden. Method `%s' is %s in class `%s'", + (METHOD_FINAL (found) ? "Final" : "Static"), + lang_printable_name (found), + (METHOD_FINAL (found) ? "final" : "static"), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + continue; + } + /* Static method can't override instance method. */ + if (METHOD_STATIC (method)) + { + parse_error_context + (method_wfl, + "Instance methods can't be overriden by a static method. Method " + "`%s' is an instance method in class `%s'", + lang_printable_name (found), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + continue; + } + /* Overriding/hiding public must be public or + overriding/hiding protected must be protected or public */ + if ((METHOD_PUBLIC (found) && !METHOD_PUBLIC (method)) || + (METHOD_PROTECTED (found) + && !(METHOD_PUBLIC (method) || METHOD_PROTECTED (method)))) + { + parse_error_context + (method_wfl, + "Methods can't be overridden to be more private. Method `%s' is " + "%s in class `%s'", lang_printable_name (found), + (METHOD_PUBLIC (found) ? "public" : "protected"), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + continue; + } + + /* If the method has default access in an other package, then + issue a warning that the current method doesn't override the one + that was found elsewhere */ + aflags = get_access_flags_from_decl (found); + if ((!aflags || (aflags > ACC_PROTECTED)) + && !class_in_current_package (DECL_CONTEXT (found))) + parse_warning_context + (method_wfl, "Method `%s' in class `%s' does not " + "override the corresponding method in class `%s', which is " + "private to a different package", + lang_printable_name (found), + IDENTIFIER_POINTER (DECL_NAME (class_decl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + + /* Check on (default) package access. FIXME. */ + /* Inheriting multiple methods with the same signature. FIXME */ + } + + TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); + + if (!seen_constructor) + { + /* No constructor seen, we craft one, at line 0 */ + int saved_lineno = lineno; + tree meth, decl; + lineno = 0; + meth = make_node (FUNCTION_TYPE); + TREE_TYPE (meth) = void_type_node; + TYPE_ARG_TYPES (meth) = NULL_TREE; + decl = add_method (class, 0, init_identifier_node, + build_java_signature (meth)); + DECL_CONSTRUCTOR_P (decl) = 1; + lineno = saved_lineno; + } +} + +/* Check abstract method of interface INTERFACE */ + +static void +java_check_abstract_methods (interface) + tree interface; +{ + int i, n; + tree method, basetype_vec, found; + + for (method = TYPE_METHODS (interface); method; method = TREE_CHAIN (method)) + { + char *csig; + tree name = DECL_NAME (method); + + /* 2- Check for double definition inside the defining interface */ + if (check_method_redefinition (interface, method)) + continue; + + /* 3- Overriding is OK as far as we preserve the return type and + the thrown exceptions */ + found = lookup_java_interface_method2 (interface, method); + if (found) + { + parse_error_context + (lookup_cl (method), + "Method `%s' previously defined in interface `%s' is " + "redefined with different return type in interface `%s'", + lang_printable_name (found), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (interface)))); + continue; + } + } + + /* 4- Inherited methods can't differ by their returned types */ + if (!(basetype_vec = TYPE_BINFO_BASETYPES (interface))) + return; + n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; i < n; i++) + { + tree sub_interface_method, sub_interface; + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + if (!vec_elt) + continue; + sub_interface = BINFO_TYPE (vec_elt); + for (sub_interface_method = TYPE_METHODS (sub_interface); + sub_interface_method; + sub_interface_method = TREE_CHAIN (sub_interface_method)) + { + found = lookup_java_interface_method2 (interface, + sub_interface_method); + if (found && (found != sub_interface_method)) + parse_error_context + (lookup_cl (sub_interface_method), + "Interface `%s' inherits method `%s' from interface `%s'. This " + "method is redefined with a different return " + "type in interface `%s'", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (interface))), + lang_printable_name (found), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (sub_interface_method)))), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + } + } +} + +/* Check the method on all the defined classes. Should be done to the + classes declared in the compilation unit only. FIXME */ + +void +java_check_methods () +{ + + tree current; + for (current = ctxp->class_list; current; current = TREE_CHAIN (current)) + if (CLASS_FROM_SOURCE_P (TREE_TYPE (current))) + { + tree class = CLASS_TO_HANDLE_TYPE (TREE_TYPE (current)); + + if (CLASS_INTERFACE (TYPE_NAME (class))) + java_check_abstract_methods (class); + else + java_check_regular_methods (current); + } +} + +/* Lookup methods in interfaces using their name and partial + signature. Return a matching method only if their types differ. */ + +static tree +lookup_java_interface_method2 (class, method_decl) + tree class, method_decl; +{ + int i, n; + tree basetype_vec = TYPE_BINFO_BASETYPES (class), to_return; + + if (!basetype_vec) + return NULL_TREE; + + n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; i < n; i++) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i), to_return; + if ((BINFO_TYPE (vec_elt) != object_type_node) + && (to_return = + lookup_java_method2 (BINFO_TYPE (vec_elt), method_decl, 1))) + return to_return; + } + for (i = 0; i < n; i++) + { + to_return = lookup_java_interface_method2 + (BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i)), method_decl); + if (to_return) + return to_return; + } + + return NULL_TREE; +} + +/* Lookup method using their name and partial signature. Return a + matching method only if their types differ. */ + +static tree +lookup_java_method2 (clas, method_decl, do_interface) + tree clas, method_decl; + int do_interface; +{ + tree method, method_signature, method_name, method_type; + method_signature = build_java_argument_signature (TREE_TYPE (method_decl)); + method_name = DECL_NAME (method_decl); + method_type = TREE_TYPE (TREE_TYPE (method_decl)); + + while (clas != NULL_TREE) + { + for (method = TYPE_METHODS (clas); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree method_sig = build_java_argument_signature (TREE_TYPE (method)); + if (DECL_NAME (method) == method_name + && method_sig == method_signature + && TREE_TYPE (TREE_TYPE (method)) != method_type) + { + return method; + } + } + clas = (do_interface ? NULL_TREE : CLASSTYPE_SUPER (clas)); + } + return NULL_TREE; +} + +/* Return the line that matches DECL line number. Used during error + report */ + +static tree +lookup_cl (decl) + tree decl; +{ + static tree cl = NULL_TREE; + + if (!decl) + return NULL_TREE; + + if (cl == NULL_TREE) + cl = build_expr_wfl (NULL_TREE, NULL, 0, 0); + + EXPR_WFL_FILENAME_NODE (cl) = get_identifier (DECL_SOURCE_FILE (decl)); + EXPR_WFL_SET_LINECOL (cl, DECL_SOURCE_LINE_FIRST (decl), -1); + + return cl; +} + +/* Look for a simple name in the single-type import list */ + +static tree +find_name_in_single_imports (name) + tree name; +{ + tree node; + + for (node = ctxp->import_list; node; node = TREE_CHAIN (node)) + if (TREE_VALUE (node) == name) + return (EXPR_WFL_NODE (TREE_PURPOSE (node))); + + return NULL_TREE; +} + +/* Process all single-type import. */ + +static int +process_imports () +{ + tree import; + int error_found; + + for (import = ctxp->import_list; import; import = TREE_CHAIN (import)) + { + tree to_be_found = EXPR_WFL_NODE (TREE_PURPOSE (import)); + + /* Don't load twice something already defined. */ + if (IDENTIFIER_CLASS_VALUE (to_be_found)) + continue; + QUALIFIED_P (to_be_found) = 1; + load_class (to_be_found, 0); + error_found = + check_pkg_class_access (to_be_found, TREE_PURPOSE (import)); + if (!IDENTIFIER_CLASS_VALUE (to_be_found)) + { + parse_error_context (TREE_PURPOSE (import), + "Class or interface `%s' not found in import", + IDENTIFIER_POINTER (to_be_found)); + return 1; + } + if (error_found) + return 1; + } + return 0; +} + +/* Possibly find a class imported by a single-type import statement. Return + 1 if an error occured, 0 otherwise. */ + +static int +find_in_imports (class_type) + tree class_type; +{ + tree import; + + for (import = ctxp->import_list; import; import = TREE_CHAIN (import)) + if (TREE_VALUE (import) == TYPE_NAME (class_type)) + { + TYPE_NAME (class_type) = EXPR_WFL_NODE (TREE_PURPOSE (import)); + QUALIFIED_P (TYPE_NAME (class_type)) = 1; + return check_pkg_class_access (TYPE_NAME (class_type), + TREE_PURPOSE (import)); + } + return 0; +} + +/* Process a import on demand statement (lazy) */ + +static int +read_import_entry (jcf, dirp, returned_name) + JCF *jcf; + DIR *dirp; + char **returned_name; +{ + if (dirp) + { + struct dirent *direntp = readdir (dirp); + if (!direntp) + { + *returned_name = NULL; + return 0; + } + else + { + *returned_name = direntp->d_name; + return (strlen (direntp->d_name)); + } + } + else + { + int current_dir_len = strlen (jcf->classname); + char *current_entry; + int current_entry_len; + + /* Here we read a zip directory as a file directory. The files + we're selecting must have the same root than the directory + we're examining. */ + + ZipDirectory *zipd = (ZipDirectory *)jcf->zipd; + + while (zipd) + { + current_entry = ZIPDIR_FILENAME (zipd); + current_entry_len = zipd->filename_length; + while (current_entry_len && current_entry [current_entry_len] != '/') + current_entry_len--; + /* If the path of the current file doesn't match the directory we're + scanning, that the end of the search */ + current_entry_len++; + if (strncmp (jcf->classname, current_entry, current_dir_len)) + { + *returned_name = NULL; + return 0; + } + /* Ok, we have at least the same path. The position of the last '/' + of the current file we're examining should match the size of + name of the directory we're browsing, otherwise that an entry + belonging to a sub directory, we want to skip it. */ + if (current_entry_len != current_dir_len) + zipd = ZIPDIR_NEXT (zipd); + else + { + jcf->zipd = ZIPDIR_NEXT (zipd); /* Prepare next read */ + *returned_name = ¤t_entry [current_entry_len]; + return (zipd->filename_length - current_entry_len); + } + } + } +} + +/* Read a import directory, gathering potential match for further type + references. Indifferently reads a filesystem or a ZIP archive + directory. */ + +static void +read_import_dir (wfl) + tree wfl; +{ + char *name = IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)); + int name_len = IDENTIFIER_LENGTH (EXPR_WFL_NODE (wfl)), reclen; + DIR *dirp = NULL; + tree dirname = ident_subst (name, name_len, "", '.', '/', ""); + JCF jcfr, *jcf, *saved_jcf = current_jcf; + char *founddirname, *d_name; + struct ZipFileCache zip_cache; + + jcf = &jcfr; + if (!classpath) + fix_classpath (); + if (!(founddirname = find_class (name, name_len, jcf, 0))) + fatal ("Can't import `%s'", name); + if (jcf->outofsynch) + jcf_out_of_synch (jcf); + if (jcf->seen_in_zip) + jcf->zipd = ZIPDIR_NEXT ((ZipDirectory *)jcf->zipd); + + else if (founddirname && (dirp = opendir (founddirname))) + { + readdir (dirp); readdir (dirp); + } + + if (!founddirname && !dirp) + { + static int first = 1; + if (first) + { + char buffer [256]; + sprintf (buffer, "Can't find default package `%s'. Check " + "the CLASSPATH environment variable and the access to the " + "archives.", name); + error (buffer); + java_error_count++; + first = 0; + } + else + parse_error_context (wfl, "Package `%s' not found in import", name); + current_jcf = saved_jcf; + return; + } + + /* Here we should have a unified way of retrieving an entry, to be + indexed. */ + while ((reclen = read_import_entry (jcf, dirp, &d_name))) + { + int java_or_class = 0; + int len; + if ((reclen > 5) + && !strcmp (&d_name [reclen-5], ".java")) + { + java_or_class = 1; + len = reclen - 5; + } + + if (!java_or_class && (reclen > 6) && + !strcmp (&d_name [reclen-6], ".class")) + { + java_or_class = 2; + len = reclen - 6; + } + + if (java_or_class) + { + char *id_name; + tree node, old; + + obstack_grow (&temporary_obstack, name, name_len); + obstack_1grow (&temporary_obstack, '/'); + obstack_grow0 (&temporary_obstack, d_name, len); + id_name = obstack_finish (&temporary_obstack); + + node = get_identifier (id_name); + IS_A_CLASSFILE_NAME (node) = 1; /* Or soon to be */ + QUALIFIED_P (node) = 1; /* As soon as we turn / into . */ + } + } + if (dirp) + closedir (dirp); + + current_jcf = saved_jcf; +} + +/* Possibly find a type in the import on demands specified + types. Returns 1 if an error occured, 0 otherwise. Run throught the + entire list, to detected potential double definitions. */ + +static int +find_in_imports_on_demand (class_type) + tree class_type; +{ + tree node, import, node_to_use; + int seen_once = -1; + tree cl; + + for (import = ctxp->import_demand_list; import; import = TREE_CHAIN (import)) + { + char *id_name; + tree found; + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (EXPR_WFL_NODE (TREE_PURPOSE (import))), + IDENTIFIER_LENGTH (EXPR_WFL_NODE (TREE_PURPOSE (import)))); + obstack_1grow (&temporary_obstack, '/'); + obstack_grow0 (&temporary_obstack, + IDENTIFIER_POINTER (TYPE_NAME (class_type)), + IDENTIFIER_LENGTH (TYPE_NAME (class_type))); + id_name = obstack_finish (&temporary_obstack); + + node = maybe_get_identifier (id_name); + if (node && IS_A_CLASSFILE_NAME (node)) + { + if (seen_once < 0) + { + cl = TREE_PURPOSE (import); + seen_once = 1; + node_to_use = node; + } + else + { + seen_once++; + parse_error_context + (import, "Type `%s' also potentially defined in package `%s'", + IDENTIFIER_POINTER (TYPE_NAME (class_type)), + IDENTIFIER_POINTER (EXPR_WFL_NODE (TREE_PURPOSE (import)))); + } + } + } + + if (seen_once == 1) + { + /* Setup lineno so that it refers to the line of the import (in + case we parse a class file and encounter errors */ + tree decl; + int saved_lineno = lineno; + lineno = EXPR_WFL_LINENO (cl); + TYPE_NAME (class_type) = ident_subst (IDENTIFIER_POINTER (node_to_use), + IDENTIFIER_LENGTH (node_to_use), + "", '/', '.', ""); + QUALIFIED_P (TYPE_NAME (class_type)) = 1; + decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)); + /* If there is no DECL set for the class or if the class isn't + loaded and not seen in source yet, the load */ + if (!decl || (!CLASS_LOADED_P (TREE_TYPE (decl)) + && !CLASS_FROM_SOURCE_P (TREE_TYPE (decl)))) + load_class (node_to_use, 0); + lineno = saved_lineno; + return check_pkg_class_access (TYPE_NAME (class_type), cl); + } + else + return (seen_once < 0 ? 0 : seen_once); /* It's ok not to have found */ +} + +/* Check that CLASS_NAME refers to a PUBLIC class. Return 0 if no + access violations were found, 1 otherwise. */ + +static int +check_pkg_class_access (class_name, cl) + tree class_name; + tree cl; +{ + tree type; + int access; + + if (!QUALIFIED_P (class_name) || !IDENTIFIER_CLASS_VALUE (class_name)) + return 0; + + if (!(type = TREE_TYPE (IDENTIFIER_CLASS_VALUE (class_name)))) + return 0; + + if (!CLASS_PUBLIC (TYPE_NAME (type))) + { + parse_error_context + (cl, "Can't access %s `%s'. Only public classes and interfaces in " + "other packages can be accessed", + (CLASS_INTERFACE (TYPE_NAME (type)) ? "interface" : "class"), + IDENTIFIER_POINTER (class_name)); + return 1; + } + return 0; +} + +/* Local variable declaration. */ + +static void +declare_local_variables (modifier, type, vlist) + int modifier; + tree type; + tree vlist; +{ + tree decl, current, returned_type, type_wfl, init_stmt = NULL_TREE; + int must_chain = 0; + + /* Push a new block if statement were seen between the last time we + pushed a block and now. Keep a cound of block to close */ + if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (current_function_decl))) + { + tree body = DECL_FUNCTION_BODY (current_function_decl); + tree b = enter_block (); + BLOCK_EXPR_ORIGIN(b) = body; + } + + if (modifier) + { + int i; + for (i = 0; i <= 10; i++) if (1 << i & modifier) break; + parse_error_context + (ctxp->modifier_ctx [i], + (modifier == ACC_FINAL ? + "Unsupported JDK1.1 `final' locals" : + "Only `final' is allowed as a local variables modifier")); + return; + } + + if (unresolved_type_p (type, &returned_type)) + { + if (returned_type) + type = returned_type; + else + { + type_wfl = type; + type = obtain_incomplete_type (type); + must_chain = 1; + } + } + + for (current = vlist; current; current = TREE_CHAIN (current)) + { + tree wfl = TREE_PURPOSE (current); + tree name = EXPR_WFL_NODE (wfl); + tree init = TREE_VALUE (current); + tree other = lookup_name_in_blocks (name); + + /* Don't try to use an INIT statement when an error was found */ + if (init && java_error_count) + init = NULL_TREE; + + if (other) + parse_error_context + (wfl, "Variable `%s' is already defined in this method and was " + "declared `%s %s' in line %d", + IDENTIFIER_POINTER (name), lang_printable_name (TREE_TYPE (other)), + IDENTIFIER_POINTER (name), DECL_SOURCE_LINE (other)); + else + { + if (!must_chain && TREE_CODE (type) == RECORD_TYPE) + type = promote_type (type); + /* Never layout this decl. This will be done when its scope + will be entered */ + decl = build_decl_no_layout (VAR_DECL, name, type); + BLOCK_CHAIN_DECL (decl); + + /* Add the initialization function to the current function's code */ + if (init) + { + tree wfl; + MODIFY_EXPR_FROM_INITIALIZATION_P (init) = 1; + java_method_add_stmt + (current_function_decl, + build_debugable_stmt (EXPR_WFL_LINECOL (init), init)); + } + + if (must_chain) + { + jdep *dep; + register_incomplete_type (JDEP_VARIABLE, type_wfl, decl, type); + dep = CLASSD_LAST (ctxp->classd_list); + JDEP_GET_PATCH (dep) = &TREE_TYPE (decl); + } + } + } + SOURCE_FRONTEND_DEBUG (("Defined locals")); +} + +/* Called during parsing. Build decls from argument list. */ + +static void +source_start_java_method (fndecl) + tree fndecl; +{ + tree tem; + tree parm_decl; + int i; + + extern tree current_binding_level; + current_function_decl = fndecl; + + /* New scope for the function */ + enter_block (); + for (tem = TYPE_ARG_TYPES (TREE_TYPE (fndecl)), i = 0; + tem != NULL_TREE; tem = TREE_CHAIN (tem), i++) + { + tree type = TREE_VALUE (tem); + tree name = TREE_PURPOSE (tem); + + /* If type is incomplete. Layout can't take place + now. Create an incomplete decl and ask for the decl to be + patched later */ + if (INCOMPLETE_TYPE_P (type)) + { + jdep *jdep; + parm_decl = build_decl_no_layout (PARM_DECL, name, type); + + register_incomplete_type (JDEP_PARM, NULL_TREE, NULL_TREE, type); + jdep = CLASSD_LAST (ctxp->classd_list); + JDEP_MISC (jdep) = name; + JDEP_GET_PATCH (jdep) = &TREE_TYPE (parm_decl); + } + else + parm_decl = build_decl (PARM_DECL, name, type); + + BLOCK_CHAIN_DECL (parm_decl); + } + tem = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)); + BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)) = + nreverse (tem); + DECL_ARG_SLOT_COUNT (current_function_decl) = i; +} + +/* Called during expansion. Push decls formerly built from argument + list so they're usable during expansion. */ + +static void +expand_start_java_method (fndecl) + tree fndecl; +{ + tree tem, *ptr; + tree parm_decl; + + extern tree current_binding_level; + current_function_decl = fndecl; + + announce_function (fndecl); + pushlevel (1); /* Push parameters */ + ptr = &DECL_ARGUMENTS (fndecl); + tem = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)); + while (tem) + { + tree next = TREE_CHAIN (tem); + DECL_ARG_TYPE (tem) = TREE_TYPE (tem); + layout_decl (tem, 0); + pushdecl (tem); + INITIALIZED_P (tem) = 1; /* Parms are initialized */ + *ptr = tem; + ptr = &TREE_CHAIN (tem); + tem = next; + } + *ptr = NULL_TREE; + pushdecl_force_head (DECL_ARGUMENTS (fndecl)); + lineno = DECL_SOURCE_LINE_FIRST (fndecl); + complete_start_java_method (fndecl); +} + +/* Terminate a function and expand its body. */ + +static void +source_end_java_method () +{ + tree fndecl = current_function_decl; + + java_parser_context_save_global (); + lineno = ctxp->last_ccb_indent1; + + /* Generate function's code */ + if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) + && ! flag_emit_class_files) + expand_expr_stmt (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl))); + + /* pop out of its parameters */ + pushdecl_force_head (DECL_ARGUMENTS (fndecl)); + poplevel (1, 0, 1); + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + /* Generate rtl for function exit. */ + if (! flag_emit_class_files) + { + lineno = DECL_SOURCE_LINE_LAST (fndecl); + expand_function_end (input_filename, lineno, 0); + + /* Run the optimizers and output assembler code for this function. */ + rest_of_compilation (fndecl); + } + + current_function_decl = NULL_TREE; + /* permanent_allocation (1); */ + java_parser_context_restore_global (); +} + +/* Record EXPR in the current function block. Complements compound + expression second operand if necessary. */ + +tree +java_method_add_stmt (fndecl, expr) + tree fndecl, expr; +{ + tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)); + tree node; + + if (java_error_count) + return body; + if ((node = add_stmt_to_compound (body, NULL_TREE, expr)) == body) + return body; + + BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) = node; + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* Add STMT to EXISTING if possible, otherwise create a new + COMPOUND_EXPR and add STMT to it. */ + +static tree +add_stmt_to_compound (existing, type, stmt) + tree existing, type, stmt; +{ + tree node; + + if (existing && (TREE_CODE (existing) == COMPOUND_EXPR) + && TREE_OPERAND (existing, 1) == size_zero_node) + { + TREE_OPERAND (existing, 1) = stmt; + TREE_TYPE (existing) = type; + return existing; + } + else if (existing) + node = build (COMPOUND_EXPR, type, existing, stmt); + else + node = build (COMPOUND_EXPR, type, stmt, size_zero_node); + + return node; +} + +/* Hold THIS for the scope of the current public method decl. */ +static tree current_this; + +/* Layout all class found during parsing */ + +void +java_layout_classes () +{ + tree current; + for (current = ctxp->class_list; current; current = TREE_CHAIN (current)) + { + current_class = TREE_TYPE (current); + TYPE_FIELDS (current_class) = nreverse (TYPE_FIELDS (current_class)); + if (!TYPE_SIZE (current_class)) + safe_layout_class (current_class); + } +} + +/* Expand all methods in all registered classes. */ + +void +java_complete_expand_methods () +{ + tree current; + + for (current = ctxp->class_list; current; current = TREE_CHAIN (current)) + { + extern tree current_constant_pool_data_ref; + tree class_type = CLASS_TO_HANDLE_TYPE (TREE_TYPE (current)); + tree decl; + int saved_lineno; + + current_class = TREE_TYPE (current); + + /* Initialize a new constant pool */ + init_outgoing_cpool (); + + /* Don't process function bodies in interfaces */ + if (!CLASS_INTERFACE (TYPE_NAME (current_class))) + for (decl = TYPE_METHODS (class_type); decl; decl = TREE_CHAIN (decl)) + { + current_function_decl = decl; + /* Don't generate debug info on line zero when expanding a + generated constructor. */ + if (DECL_CONSTRUCTOR_P (decl) && !DECL_FUNCTION_BODY (decl)) + { + /* If we found errors, it's too dangerous to try to generate + and expand a constructor */ + if (!java_error_count) + { + restore_line_number_status (1); + java_complete_expand_method (decl); + restore_line_number_status (0); + } + } + else + java_complete_expand_method (decl); + } + + /* Make the class data, register it and run the rest of decl + compilation on it */ + if (!java_error_count && ! flag_emit_class_files) + { + make_class_data (current_class); + register_class (); + rest_of_decl_compilation (TYPE_NAME (current_class), (char*) 0, 1, 0); + } + } +} + +/* Complete and expand a method. */ + +static void +java_complete_expand_method (mdecl) + tree mdecl; +{ + tree node; + jdep *current; + int no_ac_found = 1; + + /* We generate some code for an empty constructor */ + if (DECL_CONSTRUCTOR_P (mdecl) && !DECL_FUNCTION_BODY (mdecl)) + { + tree arg_list, func, call; + tree method_type = TREE_TYPE (mdecl); + tree class_type = CLASS_TO_HANDLE_TYPE (current_class); + tree self_type = (CLASSTYPE_SUPER (class_type) ? + CLASSTYPE_SUPER (class_type) : class_type); + tree method_signature = + TYPE_LANG_SPECIFIC (method_type)->signature; + tree method = + lookup_java_constructor (CLASS_TO_HANDLE_TYPE (self_type), + method_signature); + tree block, compound; + + /* Fixe the begining/ending lines of the method so that with + no_line_numbers set to 1 it doesn't generate debug info at + line 1 for this artificial constructor. */ + DECL_SOURCE_LINE (mdecl) = 1; + DECL_SOURCE_LINE_MERGE (mdecl, 1); + source_start_java_method (mdecl); + arg_list = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)); + enter_block (); + func = build_known_method_ref (method, method_type, self_type, + method_signature, arg_list); + + if (! flag_emit_class_files) + func = build1 (NOP_EXPR, build_pointer_type (method_type), func); + call = build (CALL_EXPR, TREE_TYPE (method_type), func, + build_tree_list (NULL_TREE, arg_list), NULL_TREE); + TREE_SIDE_EFFECTS (call) = 1; + call = build_class_init (self_type, call); + compound = java_method_add_stmt (mdecl, call); + block = exit_block (); + BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = block; + /* The function decl, its block and the compound statement + within this block are all of void type. */ + TREE_TYPE (block) = TREE_TYPE (compound) = + TREE_TYPE (DECL_FUNCTION_BODY (mdecl)) = void_type_node; + exit_block (); + no_ac_found = 0; + } + + if (DECL_FUNCTION_BODY (mdecl)) + { + expand_start_java_method (mdecl); + + current_this + = (!METHOD_STATIC (mdecl) ? + BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)) : NULL_TREE); + + if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) && no_ac_found) + java_complete_tree (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl))); + /* Don't go any further if we've found error(s) during the + expansion */ + if (!java_error_count) + source_end_java_method (); + } +} + +/* Expand finals. */ + +void +java_expand_finals () +{ +} + +/* Wrap non WFL PRIMARY around a WFL and set EXPR_WFL_QUALIFICATION to + a tree list node containing RIGHT. Fore coming RIGHTs will be + chained to this hook. LOCATION contains the location of the + separating `.' operator. */ + +static tree +make_qualified_primary (primary, right, location) + tree primary, right; + int location; +{ + tree wfl; + + /* We want to process THIS . xxx symbolicaly, to keep it consistent + with the way we're processing SUPER. A THIS from a primary as a + different form than a SUPER. Turn THIS into something symbolic */ + if (TREE_CODE (primary) == JAVA_THIS_EXPR) + { + wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (primary); + wfl = make_qualified_name (wfl, right, location); + PRIMARY_P (wfl) = 1; + return wfl; + } + /* Other non WFL node are wrapped around a WFL */ + else if (TREE_CODE (primary) != EXPR_WITH_FILE_LOCATION) + { + wfl = build_expr_wfl (NULL_TREE, ctxp->filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (primary); + EXPR_WFL_QUALIFICATION (wfl) = build_tree_list (primary, NULL_TREE); + } + else + { + wfl = primary; + if (!EXPR_WFL_QUALIFICATION (primary)) + EXPR_WFL_QUALIFICATION (primary) = + build_tree_list (primary, NULL_TREE); + } + + EXPR_WFL_LINECOL (right) = location; + chainon (EXPR_WFL_QUALIFICATION (wfl), build_tree_list (right, NULL_TREE)); + PRIMARY_P (wfl) = 1; + return wfl; +} + +/* Simple merge of two name separated by a `.' */ + +static tree +merge_qualified_name (left, right) + tree left, right; +{ + tree node; + obstack_grow (&temporary_obstack, IDENTIFIER_POINTER (left), + IDENTIFIER_LENGTH (left)); + obstack_1grow (&temporary_obstack, '.'); + obstack_grow0 (&temporary_obstack, IDENTIFIER_POINTER (right), + IDENTIFIER_LENGTH (right)); + node = get_identifier (obstack_base (&temporary_obstack)); + obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); + QUALIFIED_P (node) = 1; + return node; +} + +/* Merge the two parts of a qualified name into LEFT. Set the + location information of the resulting node to LOCATION, usually + inherited from the location information of the `.' operator. */ + +static tree +make_qualified_name (left, right, location) + tree left, right; + int location; +{ + int qualified; + tree left_id = EXPR_WFL_NODE (left); + tree right_id = EXPR_WFL_NODE (right); + tree wfl, merge; + + merge = merge_qualified_name (left_id, right_id); + + /* Left wasn't qualified and is now qualified */ + if (!QUALIFIED_P (left_id)) + { + tree wfl = build_expr_wfl (left_id, ctxp->filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (left); + EXPR_WFL_QUALIFICATION (left) = build_tree_list (wfl, NULL_TREE); + } + + wfl = build_expr_wfl (right_id, ctxp->filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = location; + chainon (EXPR_WFL_QUALIFICATION (left), build_tree_list (wfl, NULL_TREE)); + + EXPR_WFL_NODE (left) = merge; + return left; +} + +/* Extract the last identifier component of the qualified in WFL. The + last identifier is removed from the linked list */ + +static tree +cut_identifier_in_qualified (wfl) + tree wfl; +{ + tree q; + tree previous = NULL_TREE; + for (q = EXPR_WFL_QUALIFICATION (wfl); ; previous = q, q = TREE_CHAIN (q)) + if (!TREE_CHAIN (q)) + { + if (!previous) + fatal ("Operating on a non qualified qualified WFL - " + "cut_identifier_in_qualified"); + TREE_CHAIN (previous) = NULL_TREE; + return TREE_PURPOSE (q); + } +} + +/* Resolve the expression name NAME. Return its decl. */ + +static tree +resolve_expression_name (id) + tree id; +{ + tree name = EXPR_WFL_NODE (id); + tree decl; + + /* 6.5.5.1: Simple expression names */ + if (!PRIMARY_P (id) && !QUALIFIED_P (name)) + { + /* 15.13.1: NAME can appear within the scope of a local variable + declaration */ + if ((decl = IDENTIFIER_LOCAL_VALUE (name))) + return decl; + + /* 15.13.1: NAME can appear within a class declaration */ + else + { + decl = lookup_field_wrapper (current_class, name); + if (decl) + { + int fs = FIELD_STATIC (decl); + /* Instance variable (8.3.1.1) can't appear within + static method, static initializer or initializer for + a static variable. */ + if (!fs && METHOD_STATIC (current_function_decl)) + { + parse_error_context + (id, "Can't make a static reference to nonstatic variable " + "`%s' in class `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (DECL_NAME + (TYPE_NAME (current_class)))); + return error_mark_node; + } + decl = build_field_ref ((fs ? NULL_TREE : current_this), + current_class, name); + return (fs ? build_class_init (current_class, decl) : decl); + } + /* Fall down to error report on undefined variable */ + } + } + /* 6.5.5.2 Qualified Expression Names */ + else + { + qualify_ambiguous_name (id); + /* 15.10.1 Field Access Using a Primary and/or Expression Name */ + /* 15.10.2: Accessing Superclass Members using super */ + return resolve_field_access (id, NULL, NULL); + } + + /* We've got an error here */ + parse_error_context (id, "Undefined variable `%s'", + IDENTIFIER_POINTER (name)); + + return error_mark_node; +} + +/* 15.10.1 Field Acess Using a Primary and/or Expression Name. + We return something suitable to generate the field access. We also + return the field decl in FIELD_DECL and its type in FIELD_TYPE. If + recipient's address can be null. */ + +static tree +resolve_field_access (qual_wfl, field_decl, field_type) + tree qual_wfl; + tree *field_decl, *field_type; +{ + int is_static = 0; + tree field_ref; + tree decl, where_found, type_found; + + if (resolve_qualified_expression_name (qual_wfl, &decl, + &where_found, &type_found)) + return error_mark_node; + + /* Resolve the LENGTH field of an array here */ + if (DECL_NAME (decl) == length_identifier_node && TYPE_ARRAY_P (type_found) + && ! flag_emit_class_files) + { + tree length = build_java_array_length_access (where_found); + field_ref = + build_java_arraynull_check (type_found, length, int_type_node); + } + /* We might have been trying to resolve field.method(). In which + case, the resolution is over and decl is the answer */ + else if (DECL_P (decl) && IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) == decl) + field_ref = decl; + else if (DECL_P (decl)) + { + is_static = DECL_P (decl) && FIELD_STATIC (decl); + field_ref = build_field_ref ((is_static ? NULL_TREE : where_found), + type_found, DECL_NAME (decl)); + if (field_ref == error_mark_node) + return error_mark_node; + if (is_static) + { + field_ref = build_class_init (type_found, field_ref); + /* If the static field was identified by an expression that + needs to be generated, make the field access a compound + expression whose first part of the evaluation of the + field selector part. */ + if (where_found && TREE_CODE (where_found) != TYPE_DECL) + { + tree type = QUAL_DECL_TYPE (field_ref); + field_ref = build (COMPOUND_EXPR, type, where_found, field_ref); + } + } + } + else + field_ref = decl; + + if (field_decl) + *field_decl = decl; + if (field_type) + *field_type = QUAL_DECL_TYPE (decl); + return field_ref; +} + +/* 6.5.5.2: Qualified Expression Names */ + +static int +resolve_qualified_expression_name (wfl, found_decl, where_found, type_found) + tree wfl; + tree *found_decl, *type_found, *where_found; +{ + int from_type = 0; /* Field search initiated from a type */ + int from_super = 0, from_cast = 0; + int previous_call_static = 0; + int is_static; + tree decl = NULL_TREE, type = NULL_TREE, q; + *where_found = NULL_TREE; + + for (q = EXPR_WFL_QUALIFICATION (wfl); q; q = TREE_CHAIN (q)) + { + tree qual_wfl = QUAL_WFL (q); + + /* 15.10.1 Field Access Using a Primary */ + + switch (TREE_CODE (qual_wfl)) + { + case CALL_EXPR: + case JAVA_NEW_CLASS_EXPR: + /* If the access to the function call is a non static field, + build the code to access it. */ + if (DECL_P (decl) && !FIELD_STATIC (decl)) + { + decl = maybe_access_field (decl, *where_found, type); + if (decl == error_mark_node) + return 1; + } + /* And code for the function call */ + if (complete_function_arguments (qual_wfl)) + return 1; + *where_found = + patch_method_invocation_stmt (qual_wfl, decl, type, &is_static); + if (*where_found == error_mark_node) + return 1; + *type_found = type = QUAL_DECL_TYPE (*where_found); + + /* If the previous call was static and this one is too, + build a compound expression to hold the two (because in + that case, previous function calls aren't transported as + forcoming function's argument. */ + if (previous_call_static && is_static) + { + decl = build (COMPOUND_EXPR, type, decl, *where_found); + TREE_SIDE_EFFECTS (decl) = 1; + } + else + { + previous_call_static = is_static; + decl = *where_found; + } + continue; + + case CONVERT_EXPR: + *where_found = decl = java_complete_tree (qual_wfl); + if (decl == error_mark_node) + return 1; + *type_found = type = QUAL_DECL_TYPE (decl); + from_cast = 1; + continue; + + case ARRAY_REF: + /* If the access to the function call is a non static field, + build the code to access it. */ + if (DECL_P (decl) && !FIELD_STATIC (decl)) + { + decl = maybe_access_field (decl, *where_found, type); + if (decl == error_mark_node) + return 1; + } + /* And code for the array reference expression */ + decl = java_complete_tree (qual_wfl); + if (decl == error_mark_node) + return 1; + type = QUAL_DECL_TYPE (decl); + continue; + } + + /* If we fall here, we weren't processing a (static) function call. */ + previous_call_static = 0; + + /* It can be the keyword THIS */ + if (EXPR_WFL_NODE (qual_wfl) == this_identifier_node) + { + if (!current_this) + { + parse_error_context + (wfl, "Keyword `this' used outside allowed context"); + return 1; + } + /* We have to generate code for intermediate acess */ + *where_found = decl = current_this; + type = QUAL_DECL_TYPE (decl); + continue; + } + + /* 15.10.2 Accessing Superclass Members using SUPER */ + if (EXPR_WFL_NODE (qual_wfl) == super_identifier_node) + { + tree node; + /* Check on the restricted use of SUPER */ + if (METHOD_STATIC (current_function_decl) + || current_class == object_type_node) + { + parse_error_context + (wfl, "Keyword `super' used outside allowed context"); + return 1; + } + /* Otherwise, treat SUPER as (SUPER_CLASS)THIS */ + node = build_cast (EXPR_WFL_LINECOL (qual_wfl), + CLASSTYPE_SUPER (current_class), + build_this (EXPR_WFL_LINECOL (qual_wfl))); + *where_found = decl = java_complete_tree (node); + *type_found = type = QUAL_DECL_TYPE (decl); + from_super = from_type = 1; + continue; + } + + /* 15.13.1: Can't search for field name in packages, so we + assume a variable/class name was meant. */ + if (RESOLVE_PACKAGE_NAME_P (qual_wfl)) + { + if (from_super || from_cast) + parse_error_context + ((from_cast ? qual_wfl : wfl), + "No variable `%s' defined in class `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)), + lang_printable_name (type)); + else + parse_error_context + (qual_wfl, "Undefined variable or class name: `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl))); + return 1; + } + + /* We have a type name. It's been already resolved when the + expression was qualified. */ + else if (RESOLVE_TYPE_NAME_P (qual_wfl)) + { + if (!(decl = QUAL_RESOLUTION (q))) + return 1; /* Error reported already */ + + if (not_accessible_p (TREE_TYPE (decl), decl, 0)) + { + parse_error_context + (qual_wfl, "Can't access %s field `%s.%s' from `%s'", + java_accstring_lookup (get_access_flags_from_decl (decl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), + IDENTIFIER_POINTER (DECL_NAME (decl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)))); + return 1; + } + + type = TREE_TYPE (decl); + from_type = 1; + } + /* We resolve and expression name */ + else + { + tree field_decl; + + /* If there exists an early resolution, use it. That occurs + only once and we know that there are more things to + come. Don't do that when processing something after SUPER + (we need more thing to be put in place below */ + if (!from_super && QUAL_RESOLUTION (q)) + decl = QUAL_RESOLUTION (q); + + /* We have to search for a field, knowing the type of its + container. The flag FROM_TYPE indicates that we resolved + the last member of the expression as a type name, which + means that for the resolution of this field, will check + on other errors than if the it was resolved as a member + of an other field. */ + else + { + int is_static; + if (!from_type && !JREFERENCE_TYPE_P (type)) + { + parse_error_context + (qual_wfl, "Attempt to reference field `%s' in `%s %s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)), + lang_printable_name (type), + IDENTIFIER_POINTER (DECL_NAME (field_decl))); + return 1; + } + + if (!(field_decl = + lookup_field_wrapper (type, EXPR_WFL_NODE (qual_wfl)))) + { + parse_error_context + (qual_wfl, "No variable `%s' defined in class `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + return 1; + } + + /* Check on accessibility here */ + if (not_accessible_p (type, field_decl, from_super)) + { + parse_error_context + (qual_wfl, + "Can't access %s field `%s.%s' from `%s'", + java_accstring_lookup + (get_access_flags_from_decl (field_decl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), + IDENTIFIER_POINTER (DECL_NAME (field_decl)), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (current_class)))); + return 1; + } + + /* There are things to check when fields are accessed + from type. There are no restrictions on a static + declaration of the field when it is accessed from an + interface */ + is_static = FIELD_STATIC (field_decl); + if (!from_super && from_type + && !TYPE_INTERFACE_P (type) && !is_static) + { + parse_error_context + (qual_wfl, "Can't make a static reference to nonstatic " + "variable `%s' in class `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + return 1; + } + from_cast = from_super = 0; + + /* If we need to generate something to get a proper handle + on what this field is accessed from, do it now. */ + if (!is_static) + { + decl = maybe_access_field (decl, *where_found, type); + if (decl == error_mark_node) + return 1; + } + + /* We want to keep the location were found it, and the type + we found. */ + *where_found = decl; + *type_found = type; + + /* This is the decl found and eventually the next one to + search from */ + decl = field_decl; + } + + from_type = 0; + type = QUAL_DECL_TYPE (decl); + } + } + *found_decl = decl; + return 0; +} + +/* 6.6 Qualified name and access control. Returns 1 if MEMBER (a decl) + can't be accessed from REFERENCE (a record type). */ + +int not_accessible_p (reference, member, from_super) + tree reference, member; + int from_super; +{ + int access_flag = get_access_flags_from_decl (member); + + /* Access always granted for members declared public */ + if (access_flag & ACC_PUBLIC) + return 0; + + /* Check access on protected members */ + if (access_flag & ACC_PROTECTED) + { + /* Access granted if it occurs from within the package + containing the class in which the protected member is + declared */ + if (class_in_current_package (DECL_CONTEXT (member))) + return 0; + + if (TREE_CODE (member) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (member)) + { + /* Access from SUPER is granted */ + if (from_super) + return 0; + /* Otherwise, access isn't granted */ + return 1; + } + else + { + /* If accessed with the form `super.member', then access is + granted */ + if (from_super) + return 0; + + /* Otherwise, access is granted if occuring from the class where + member is declared or a subclass of it */ + if (inherits_from_p (reference, current_class)) + return 0; + } + return 1; + } + + /* Check access on private members. Access is granted only if it + occurs from within the class in witch it is declared*/ + + if (access_flag & ACC_PRIVATE) + return (current_class == DECL_CONTEXT (member) ? 0 : 1); + + /* Default access are permitted only when occuring within the + package in which the type (REFERENCE) is declared. In other words, + REFERENCE is defined in the current package */ + if (ctxp->package) + return !class_in_current_package (reference); + + /* Otherwise, access is granted */ + return 0; +} + +/* Returns 1 if class was declared in the current package, 0 otherwise */ + +static int +class_in_current_package (class) + tree class; +{ + static tree cache = NULL_TREE; + int qualified_flag; + tree left; + + if (cache == class) + return 1; + + qualified_flag = QUALIFIED_P (DECL_NAME (TYPE_NAME (class))); + + /* If the current package is empty and the name of CLASS is + qualified, class isn't in the current package. If there is a + current package and the name of the CLASS is not qualified, class + isn't in the current package */ + if (!ctxp->package && qualified_flag || ctxp->package && !qualified_flag) + return 0; + + /* If there is not package and the name of CLASS isn't qualified, + they belong to the same unnamed package */ + if (!ctxp->package && !qualified_flag) + return 1; + + /* Compare the left part of the name of CLASS with the package name */ + breakdown_qualified (&left, NULL, DECL_NAME (TYPE_NAME (class))); + if (ctxp->package == left) + { + cache = class; + return 1; + } + return 0; +} + +/* This function may generate code to access DECL from WHERE. This is + done only if certain conditions meet. */ + +static tree +maybe_access_field (decl, where, type) + tree decl, where, type; +{ + if (DECL_P (decl) && decl != current_this + && (!(TREE_CODE (decl) != PARM_DECL + && FIELD_STATIC (decl))) + && !IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl))) + decl = build_field_ref (where ? where : current_this, + type, DECL_NAME (decl)); + return decl; +} + +/* Build a method invocation statement, by patching PATCH. If non NULL + and according to the situation, PRIMARY and WHERE may be + used. IS_STATIC is set to 1 if the invoked function is static. */ + +static tree +patch_method_invocation_stmt (patch, primary, where, is_static) + tree patch, primary, where; + int *is_static; +{ + tree wfl = TREE_OPERAND (patch, 0); + tree args = TREE_OPERAND (patch, 1); + tree name = EXPR_WFL_NODE (wfl); + tree list, class_type; + + /* Should be overriden if everything goes well. Otherwise, if + something fails, it should keep this value. It stop the + evaluation of a bogus assignment. See java_complete_tree, + MODIFY_EXPR: for the reasons why we sometimes want to keep on + evaluating an assignment */ + TREE_TYPE (patch) = error_mark_node; + + /* Since lookup functions are messing with line numbers, save the + context now. */ + java_parser_context_save_global (); + + /* 15.11.1: Compile-Time Step 1: Determine Class or Interface to Search */ + + /* Resolution of qualified name, excluding constructors */ + if (QUALIFIED_P (name) && !CALL_CONSTRUCTOR_P (patch)) + { + tree class_decl, identifier, identifier_wfl; + /* Extract the last IDENTIFIER of the qualified + expression. This is a wfl and we will use it's location + data during error report. */ + identifier_wfl = cut_identifier_in_qualified (wfl); + identifier = EXPR_WFL_NODE (identifier_wfl); + + /* Given the context, IDENTIFIER is syntactically qualified + as a MethodName. We need to qualify what's before */ + qualify_ambiguous_name (wfl); + + /* Package resolution are erroneous */ + if (RESOLVE_PACKAGE_NAME_P (wfl)) + { + tree remainder; + breakdown_qualified (&remainder, NULL, EXPR_WFL_NODE (wfl)); + parse_error_context (wfl, "Can't search method `%s' in package " + "`%s'",IDENTIFIER_POINTER (identifier), + IDENTIFIER_POINTER (remainder)); + return error_mark_node; + } + /* We're resolving a call from a type */ + else if (RESOLVE_TYPE_NAME_P (wfl)) + { + tree decl = QUAL_RESOLUTION (EXPR_WFL_QUALIFICATION (wfl)); + tree name = DECL_NAME (decl); + tree type; + + class_decl = resolve_and_layout (name, wfl); + if (CLASS_INTERFACE (decl)) + { + parse_error_context + (identifier_wfl, "Can't make static reference to method " + "`%s' in interface `%s'", IDENTIFIER_POINTER (identifier), + IDENTIFIER_POINTER (name)); + return error_mark_node; + } + /* Look the method up in the type selector. The method ought + to be static. */ + type = TREE_TYPE (class_decl); + list = lookup_method_invoke (0, wfl, type, identifier, args); + if (list && !METHOD_STATIC (list)) + { + char *fct_name = strdup ((char *)lang_printable_name (list)); + parse_error_context + (identifier_wfl, + "Can't make static reference to method `%s %s' in class `%s'", + lang_printable_name (TREE_TYPE (TREE_TYPE (list))), fct_name, + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + free (fct_name); + return error_mark_node; + } + } + /* We're resolving an expression name */ + else + { + tree field, type; + + /* 1- Find the field to which the call applies */ + field = resolve_field_access (wfl, NULL, &type); + if (field == error_mark_node) + return error_mark_node; + + /* 2- Do the layout of the class where the last field + was found, so we can search it. */ + class_decl = + resolve_and_layout (DECL_NAME (TYPE_NAME (type)), NULL_TREE); + + /* 3- Retrieve a filtered list of method matches, Refine + if necessary. In any cases, point out errors. */ + list = lookup_method_invoke (0, identifier_wfl, type, + identifier, args); + + /* 4- Add the field as an argument */ + args = tree_cons (NULL_TREE, field, args); + } + + /* CLASS_TYPE is used during the call to not_accessible_p and + IDENTIFIER_WFL will be used to report any problem further */ + class_type = TREE_TYPE (class_decl); + wfl = identifier_wfl; + } + /* Resolution of simple names, names generated after a primary: or + constructors */ + else + { + tree class_to_search; + int lc; /* Looking for Constructor */ + + /* We search constructor in their target class */ + if (CALL_CONSTRUCTOR_P (patch)) + { + class_to_search = resolve_no_layout (EXPR_WFL_NODE (wfl), NULL_TREE); + if (!class_to_search) + { + parse_error_context + (wfl, "Class `%s' not found in type declaration", + IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl))); + return error_mark_node; + } + + /* Can't instantiate an abstract class */ + if (CLASS_ABSTRACT (class_to_search)) + { + parse_error_context + (wfl, "Class `%s' is an abstract class. It can't be " + "instantiated", IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl))); + return error_mark_node; + } + class_to_search = TREE_TYPE (class_to_search); + lc = 1; + } + /* This is a regular search in the local class, unless an + alternate class is specified. */ + else + { + class_to_search = (where ? where : current_class); + lc = 0; + } + + /* NAME is a simple identifier or comes from a primary. Search + in the class whose declaration contain the method being + invoked. */ + list = lookup_method_invoke (lc, wfl, class_to_search, name, args); + + /* Don't continue if no method were found, as the next statement + can't be executed then. */ + if (!list) return error_mark_node; + + /* Check for static reference if non static methods */ + if (check_for_static_method_reference (wfl, patch, list, + class_to_search, primary)) + return error_mark_node; + + /* Non static/constructor methods are called with the current + object extra argument. If method is resolved as a primary, + use the primary otherwise use the current THIS. */ + if (!CALL_CONSTRUCTOR_P (patch) && !METHOD_STATIC (list)) + args = tree_cons (NULL_TREE, primary ? primary : current_this, args); + + class_type = class_to_search; + } + + /* Merge point of all resolution schemes. If we have nothing, this + is an error, already signaled */ + if (!list) return error_mark_node; + + /* Check accessibility, position the is_static flag, build and + return the call */ + if (not_accessible_p (class_type, list, 0)) + { + char *fct_name = strdup ((char *)lang_printable_name (list)); + parse_error_context + (wfl, "Can't access %s method `%s %s.%s' from `%s'", + java_accstring_lookup (get_access_flags_from_decl (list)), + lang_printable_name (TREE_TYPE (TREE_TYPE (list))), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class_type))), fct_name, + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)))); + free (fct_name); + return error_mark_node; + } + + if (is_static) + *is_static = METHOD_STATIC (list); + java_parser_context_restore_global (); + return patch_invoke (patch, list, args, wfl); +} + +/* Check that we're not trying to do a static reference to a method in + non static method. Return 1 if it's the case, 0 otherwise. */ + +static int +check_for_static_method_reference (wfl, node, method, where, primary) + tree wfl, node, method, where, primary; +{ + if (METHOD_STATIC (current_function_decl) + && !METHOD_STATIC (method) && !primary && !CALL_CONSTRUCTOR_P (node)) + { + char *fct_name = strdup ((char *)lang_printable_name (method)); + parse_error_context + (wfl, "Can't make static reference to method `%s %s' in class `%s'", + lang_printable_name (TREE_TYPE (TREE_TYPE (method))), fct_name, + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (where)))); + free (fct_name); + return 1; + } + return 0; +} + +/* Patch an invoke expression METHOD and ARGS, based on its invocation + mode. */ + +static tree +patch_invoke (patch, method, args, cl) + tree patch, method, args; + tree cl; +{ + tree dtable, func; + tree signature = build_java_signature (TREE_TYPE (method)); + tree original_call; + + switch (invocation_mode (method, 0)) + { + case INVOKE_VIRTUAL: + dtable = invoke_build_dtable (0, args); + func = build_invokevirtual (dtable, method); + break; + case INVOKE_STATIC: + func = build_known_method_ref (method, TREE_TYPE (method), + DECL_CONTEXT (method), + signature, args); + args = nreverse (args); + break; + + default: + fatal ("Unknown invocation mode - build_invoke"); + return NULL_TREE; + } + + + /* Ensure self_type is initialized, (invokestatic). FIXME */ + func = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (method)), func); + TREE_TYPE (patch) = TREE_TYPE (TREE_TYPE (method)); + TREE_OPERAND (patch, 0) = func; + TREE_OPERAND (patch, 1) = args; + original_call = patch; + + /* We're calling a constructor. New is called an its returned value + is an argument to the constructor. We build a COMPOUND_EXPR and + use saved expression so that the overall NEW expression value is + a pointer to a newly created and initialized class. */ + if (CALL_CONSTRUCTOR_P (original_call)) + { + tree class = DECL_CONTEXT (method); + tree c1, saved_new, size, new; + if (!TYPE_SIZE (class)) + safe_layout_class (class); + size = size_in_bytes (class); + new = build (CALL_EXPR, promote_type (class), + build_address_of (alloc_object_node), + tree_cons (NULL_TREE, build_class_ref (class), + build_tree_list (NULL_TREE, + size_in_bytes (class))), + NULL_TREE); + saved_new = save_expr (new); + c1 = build_tree_list (NULL_TREE, saved_new); + TREE_CHAIN (c1) = TREE_OPERAND (original_call, 1); + TREE_OPERAND (original_call, 1) = c1; + TREE_SET_CODE (original_call, CALL_EXPR); + patch = build (COMPOUND_EXPR, TREE_TYPE (new), patch, saved_new); + } + return patch; +} + +static int +invocation_mode (method, super) + tree method; + int super; +{ + int access = get_access_flags_from_decl (method); + + if (access & ACC_STATIC) + return INVOKE_STATIC; + + if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method)))) + return INVOKE_STATIC; + + if (super) + return INVOKE_SUPER; + + if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))) + return INVOKE_INTERFACE; + + if (DECL_CONSTRUCTOR_P (method)) + return INVOKE_STATIC; + + return INVOKE_VIRTUAL; +} + +/* Retrieve a refined list of matching methods. */ + +static tree +lookup_method_invoke (lc, cl, class, name, arg_list) + int lc; + tree cl; + tree class, name, arg_list; +{ + tree method = make_node (FUNCTION_TYPE); + tree arg_type_list = NULL_TREE; + tree signature, list, node, scratch; + + for (node = arg_list; node; node = TREE_CHAIN (node)) + { + tree current_arg; + current_arg = + build_tree_list (NULL_TREE, + promote_type (TREE_TYPE (TREE_VALUE (node)))); + arg_type_list = chainon (current_arg, arg_type_list); + } + TYPE_ARG_TYPES (method) = arg_type_list; + + if (!lc) + { + signature = build_java_argument_signature (method); + list = match_java_method (class, name, signature); + list = refine_accessible_methods_list (lc, list); + } + else + { + TREE_TYPE (method) = void_type_node; + signature = build_java_signature (method); + list = lookup_java_constructor (class, signature); + } + + if (!list) + { + parse_error_context (cl, "Can't find method `%s(%s)' in class `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (signature), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class)))); + return NULL_TREE; + } + + if (lc) + return list; + + if (TREE_CHAIN (list)) + { + tree most_specific_list = NULL_TREE; + tree current; + /* 15.11.2.2 Choose the Most Specific Method */ + for (current = list; current; current = TREE_CHAIN (current)) + { + tree rest; + tree method = TREE_VALUE (list); + tree class_from = DECL_CONTEXT (method); + for (rest = TREE_CHAIN (current); rest; rest = TREE_CHAIN (rest)) + { + tree other = TREE_VALUE (rest); + + /* METHOD can be declared more specific with regard to OTHER iif: + + - The class METHOD belongs can be converted to the + class OTHER belongs by method invocation conversion + (5.3). Since we're dealing with classes here, it is + covered by the identity conversion or the windening + primitive conversion. + + - The types of the arguments of METHOD can be + converted to the types of the arguments of OTHER by + method invocation conversion (5.3). */ + + if (valid_ref_assignconv_cast_p (class_from, + DECL_CONTEXT (other), 0) + && 1) /* Test on args non implemented */ + most_specific_list = tree_cons (NULL_TREE, method, + most_specific_list); + } + } + list = most_specific_list; + } + + if (!list || TREE_CHAIN (list)) + { + parse_error_context (cl, "Can't find method `%s(%s)' in class `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (signature), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class)))); + return NULL_TREE; + } + + /* 15.11.3 Is the Chosen Method Appropriate ? */ + else + return TREE_VALUE (list); +} + +/* Refine accessible methods from the raw matching method list, as + specified in 15.11.4.3. Return a (possibly empty) new method + list. */ + +static tree +refine_accessible_methods_list (lc, list) + int lc; /* Looking for Constructor */ + tree list; +{ +#define ADD_TO_LIST_AND_CONTINUE \ + { \ + refined_list = tree_cons (NULL_TREE, method, refined_list); \ + continue; \ + } + tree node, refined_list = NULL_TREE; + tree current_class_name = DECL_NAME (TYPE_NAME (current_class)); + + for (node = list; node; node = TREE_CHAIN (node)) + { + int access, identical; + tree class_from, method, class_from_name; + + method = TREE_VALUE (node); + + /* Constructor not retained here, unless were specifically + looking for them. */ + if (lc && DECL_CONSTRUCTOR_P (method)) + ADD_TO_LIST_AND_CONTINUE; + + access = get_access_flags_from_decl (method); + class_from = DECL_CONTEXT (method); + class_from_name = DECL_NAME (TYPE_NAME (class_from)); + + identical = identical_subpath_p (current_class_name, class_from_name); + + /* Check accessibility of class_from from the current one: This + test has been already carried out when qualify_ambiguous_name + tried to resolve a type found in an other package. It is not + necessary to retest things here, the error has been already + reported. */ + + /* Public method are always OK */ + if (access & ACC_PUBLIC) + ADD_TO_LIST_AND_CONTINUE; + + /* Protected method access is OK if classes are from the + same package or part of the same inheritance lineage */ + if ((access & ACC_PROTECTED) + && (inherits_from_p (current_class, class_from) || identical)) + ADD_TO_LIST_AND_CONTINUE; + + /* Methods with default (package) access are OK if classes are + from the same default package. */ + if (identical || + (!QUALIFIED_P (class_from_name) && !QUALIFIED_P (current_class_name))) + ADD_TO_LIST_AND_CONTINUE; + + /* Private method accessible iff current class is the node where + the method is defined */ + if ((access & ACC_PRIVATE) && (class_from == current_class)) + ADD_TO_LIST_AND_CONTINUE; + } +#undef ADD_TO_LIST_AND_CONTINUE + return refined_list; +} + +/* Qualification routines */ + +static void +qualify_ambiguous_name (id) + tree id; +{ + tree qual, qual_wfl, name, decl, ptr_type, saved_current_class; + int again, super_found = 0, this_found = 0; + + /* We first qualify the first element, then derive qualification of + others based on the first one. If the first element is qualified + by a resolution (field or type), this resolution is stored in the + QUAL_RESOLUTION of the qual element being examined. We need to + save the current_class since the use of SUPER might change the + its value. */ + saved_current_class = current_class; + qual = EXPR_WFL_QUALIFICATION (id); + do { + + /* Simple qualified expression feature a qual_wfl that is a + WFL. Expression derived from a primary feature more complicated + things like a CALL_EXPR. Expression from primary need to be + worked out to extract the part on which the qualification will + take place. */ + qual_wfl = QUAL_WFL (qual); + switch (TREE_CODE (qual_wfl)) + { + case CALL_EXPR: + qual_wfl = TREE_OPERAND (qual_wfl, 0); + if (TREE_CODE (qual_wfl) != EXPR_WITH_FILE_LOCATION) + { + qual = EXPR_WFL_QUALIFICATION (qual_wfl); + qual_wfl = QUAL_WFL (qual); + } + break; + case JAVA_NEW_CLASS_EXPR: + case CONVERT_EXPR: + case ARRAY_REF: + qual_wfl = TREE_OPERAND (qual_wfl, 0); + break; + } + name = EXPR_WFL_NODE (qual_wfl); + ptr_type = current_class; + again = 0; + /* If we have a THIS (from a primary), we set the context accordingly */ + if (name == this_identifier_node) + { + qual = TREE_CHAIN (qual); + qual_wfl = QUAL_WFL (qual); + name = EXPR_WFL_NODE (qual_wfl); + this_found = 1; + } + /* If we have a SUPER, we set the context accordingly */ + if (name == super_identifier_node) + { + current_class = CLASSTYPE_SUPER (ptr_type); + /* Check that there is such a thing as a super class. If not, + return. The error will be caught later on, during the + resolution */ + if (!current_class) + { + current_class = saved_current_class; + return; + } + qual = TREE_CHAIN (qual); + /* Do one more interation to set things up */ + super_found = again = 1; + } + } while (again); + + /* If name appears within the scope of a location variable + declaration or parameter declaration, then it is an expression + name. We don't carry this test out if we're in the context of the + use of SUPER or THIS */ + + if (!this_found && !super_found && (decl = IDENTIFIER_LOCAL_VALUE (name))) + { + RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1; + QUAL_RESOLUTION (qual) = decl; + } + + /* If within the class/interface NAME was found to be used there + exists a (possibly inherited) field named NAME, then this is an + expression name. */ + else if ((decl = lookup_field_wrapper (ptr_type, name))) + { + RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1; + QUAL_RESOLUTION (qual) = decl; + } + + /* We reclassify NAME as a type name if: + - NAME is a class/interface declared within the compilation + unit containing NAME, + - NAME is imported via a single-type-import declaration, + - NAME is declared in an another compilation unit of the package + of the compilation unit containing NAME, + - NAME is declared by exactly on type-import-on-demand declaration + of the compilation unit containing NAME. */ + else if ((decl = resolve_and_layout (name, NULL_TREE))) + { + RESOLVE_TYPE_NAME_P (qual_wfl) = 1; + QUAL_RESOLUTION (qual) = decl; + } + + /* Method call are expression name */ + else if (TREE_CODE (QUAL_WFL (qual)) == CALL_EXPR) + RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1; + + /* Check here that NAME isn't declared by more than one + type-import-on-demand declaration of the compilation unit + containing NAME. FIXME */ + + /* Otherwise, NAME is reclassified as a package name */ + else + RESOLVE_PACKAGE_NAME_P (qual_wfl) = 1; + + /* Propagate the qualification accross other components of the + qualified name */ + for (qual = TREE_CHAIN (qual); qual; + qual_wfl = QUAL_WFL (qual), qual = TREE_CHAIN (qual)) + { + if (RESOLVE_PACKAGE_NAME_P (qual_wfl)) + RESOLVE_PACKAGE_NAME_P (QUAL_WFL (qual)) = 1; + else + RESOLVE_EXPRESSION_NAME_P (QUAL_WFL (qual)) = 1; + } + + /* Store the global qualification for the ambiguous part of ID back + into ID fields */ + if (RESOLVE_EXPRESSION_NAME_P (qual_wfl)) + RESOLVE_EXPRESSION_NAME_P (id) = 1; + else if (RESOLVE_TYPE_NAME_P (qual_wfl)) + RESOLVE_TYPE_NAME_P (id) = 1; + else if (RESOLVE_PACKAGE_NAME_P (qual_wfl)) + RESOLVE_PACKAGE_NAME_P (id) = 1; + + /* Restore the current class */ + current_class = saved_current_class; +} + +static int +breakdown_qualified (left, right, source) + tree *left, *right, source; +{ + char *p = IDENTIFIER_POINTER (source), *base; + int l = IDENTIFIER_LENGTH (source); + + /* Breakdown NAME into REMAINDER . IDENTIFIER */ + base = p; + p += (l-1); + while (*p != '.' && p != base) + p--; + + /* We didn't find a '.'. Return an error */ + if (p == base) + return 1; + + *p = '\0'; + if (right) + *right = get_identifier (p+1); + *left = get_identifier (IDENTIFIER_POINTER (source)); + *p = '.'; + + return 0; +} + +/* Return 1 if N1 and N2 have identical sub-path. */ + +static int +identical_subpath_p (n1, n2) + tree n1, n2; +{ + tree left1, left2; + + if (!QUALIFIED_P (n1) || !QUALIFIED_P (n2)) + return n1 == n2; + + breakdown_qualified (&left1, NULL, n1); + breakdown_qualified (&left2, NULL, n2); + + return left1 == left2; +} + +static int +not_initialized_as_it_should_p (decl) + tree decl; +{ + if (DECL_P (decl)) + { + if (TREE_CODE (decl) == FIELD_DECL + && METHOD_STATIC (current_function_decl)) + return 0; + return DECL_P (decl) && !INITIALIZED_P (decl); + } + return 0; +} + +/* Patch tree nodes in a function body. When a BLOCK is found, push + local variable decls if present. */ + +static tree +java_complete_tree (node) + tree node; +{ + tree nn, cn, wfl_op1, wfl_op2; + int flag, location; + + /* CONVERT_EXPR always has its type set, even though it needs to be + worked out */ + if (TREE_TYPE (node) && TREE_CODE (node) != CONVERT_EXPR) + return node; + + /* The switch block implements cases processing container nodes + first. Contained nodes are always written back. Leaves come + next and return a value. */ + switch (TREE_CODE (node)) + { + case BLOCK: + + /* 1- Block section. + Set the local values on decl names so we can identify them + faster when they're referenced. At that stage, identifiers + are legal so we don't check for declaration errors. */ + for (cn = BLOCK_EXPR_DECLS (node); cn; cn = TREE_CHAIN (cn)) + { + DECL_CONTEXT (cn) = current_function_decl; + IDENTIFIER_LOCAL_VALUE (DECL_NAME (cn)) = cn; + INITIALIZED_P (cn) = 0; + } + if (BLOCK_EXPR_BODY (node)) + { + BLOCK_EXPR_BODY (node) = java_complete_tree (BLOCK_EXPR_BODY (node)); + if (BLOCK_EXPR_BODY (node) == error_mark_node) + return error_mark_node; + } + /* Turn local bindings to null */ + for (cn = BLOCK_EXPR_DECLS (node); cn; cn = TREE_CHAIN (cn)) + IDENTIFIER_LOCAL_VALUE (DECL_NAME (cn)) = NULL_TREE; + + TREE_TYPE (node) = void_type_node; + break; + + /* 2- They are expressions but ultimately deal with statements */ + case LABELED_BLOCK_EXPR: + PUSH_LABELED_BLOCK (node); + if (LABELED_BLOCK_BODY (node)) + COMPLETE_CHECK_OP_1 (node); + TREE_TYPE (node) = void_type_node; + POP_LABELED_BLOCK (); + return node; + + case EXIT_BLOCK_EXPR: + /* We don't complete operand 1, because it's the return value of + the EXIT_BLOCK_EXPR which doesn't exist it Java */ + return patch_bc_statement (node); + + case LOOP_EXPR: + PUSH_LOOP (node); + /* Check whether the loop was enclosed in a labeled + statement. If not, create one, insert the loop in it and + return the node */ + nn = patch_loop_statement (node); + /* Anyways, walk the body of the loop */ + TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0)); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + TREE_TYPE (nn) = TREE_TYPE (node) = void_type_node; + /* If we returned something different, that's because we + inserted a label. Pop the label too. */ + if (nn != node) + POP_LABELED_BLOCK (); + POP_LOOP (); + return nn; + + case EXIT_EXPR: + TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0)); + return patch_exit_expr (node); + + case COND_EXPR: + /* Condition */ + TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0)); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + /* then-else branches */ + TREE_OPERAND (node, 1) = java_complete_tree (TREE_OPERAND (node, 1)); + if (TREE_OPERAND (node, 1) == error_mark_node) + return error_mark_node; + TREE_OPERAND (node, 2) = java_complete_tree (TREE_OPERAND (node, 2)); + if (TREE_OPERAND (node, 2) == error_mark_node) + return error_mark_node; + return patch_if_else_statement (node); + break; + + /* 3- Expression section */ + case COMPOUND_EXPR: + TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0)); + TREE_OPERAND (node, 1) = java_complete_tree (TREE_OPERAND (node, 1)); + if (TREE_OPERAND (node, 1) == error_mark_node) + return error_mark_node; + TREE_TYPE (node) = TREE_TYPE (TREE_OPERAND (node, 1)); + break; + + case RETURN_EXPR: + return patch_return (node); + + case EXPR_WITH_FILE_LOCATION: + if (!EXPR_WFL_NODE (node) /* Or a PRIMARY flag ? */ + || TREE_CODE (EXPR_WFL_NODE (node)) == IDENTIFIER_NODE) + return resolve_expression_name (node); + else + { + EXPR_WFL_NODE (node) = java_complete_tree (EXPR_WFL_NODE (node)); + TREE_SIDE_EFFECTS (node) = 1; + if (EXPR_WFL_NODE (node) == error_mark_node) + { + /* Its important for the evaluation of assignment that + this mark on the TREE_TYPE is propagated. */ + TREE_TYPE (node) = error_mark_node; + return error_mark_node; + } + else + TREE_TYPE (node) = TREE_TYPE (EXPR_WFL_NODE (node)); + } + break; + + case JAVA_NEW_ARRAY_EXPR: + /* Patch all the dimensions */ + flag = 0; + for (cn = TREE_OPERAND (node, 1); cn; cn = TREE_CHAIN (cn)) + { + int location = EXPR_WFL_LINECOL (TREE_VALUE (cn)); + tree dim = java_complete_tree (TREE_VALUE (cn)); + if (dim == error_mark_node) + { + flag = 1; + continue; + } + else + { + TREE_VALUE (cn) = save_expr (dim); + /* Setup the location of the current dimension, for + later error report. */ + TREE_PURPOSE (cn) = + build_expr_wfl (NULL_TREE, input_filename, 0, 0); + EXPR_WFL_LINECOL (TREE_PURPOSE (cn)) = location; + } + } + /* They complete the array creation expression, if no errors + were found. */ + return (flag ? error_mark_node : patch_newarray (node)); + + case JAVA_NEW_CLASS_EXPR: + case CALL_EXPR: + /* Complete function's argument first */ + if (complete_function_arguments (node)) + return error_mark_node; + else + return patch_method_invocation_stmt (node, NULL_TREE, NULL_TREE, NULL); + + case MODIFY_EXPR: + /* Save potential wfls */ + wfl_op1 = TREE_OPERAND (node, 0); + wfl_op2 = TREE_OPERAND (node, 1); + TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + + if (COMPOUND_ASSIGN_P (wfl_op2)) + { + tree lvalue; + tree other = + java_complete_tree (TREE_OPERAND (wfl_op2, 0)); + + /* Hand stablize the lhs on both places */ + lvalue = stabilize_reference (other); + TREE_OPERAND (node, 0) = lvalue; + TREE_OPERAND (TREE_OPERAND (node, 1), 0) = lvalue; + } + + /* There are cases where the type of RHS is fixed. In those + cases, if the evaluation of the RHS fails, we further the + evaluation of the assignment to detect more errors. */ + nn = java_complete_tree (TREE_OPERAND (node, 1)); + if (nn == error_mark_node) + { + /* It's hopeless, but we can further things on to discover + an error during the assignment. In any cases, the + assignment operation fails. */ + if (TREE_CODE (TREE_OPERAND (node, 1)) != EXPR_WITH_FILE_LOCATION + && TREE_TYPE (TREE_OPERAND (node, 1)) != error_mark_node) + patch_assignment (node, wfl_op1, wfl_op2); + + /* Now, we still mark the lhs as initialized */ + if (DECL_P (TREE_OPERAND (node, 0))) + INITIALIZED_P (TREE_OPERAND (node, 0)) = 1; + + return error_mark_node; + } + TREE_OPERAND (node, 1) = nn; + return patch_assignment (node, wfl_op1, wfl_op2); + + case MULT_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case URSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_XOR_EXPR: + case BIT_IOR_EXPR: + case TRUNC_MOD_EXPR: + case RDIV_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case EQ_EXPR: + case NE_EXPR: + case GT_EXPR: + case GE_EXPR: + case LT_EXPR: + case LE_EXPR: + /* Operands 0 and 1 are WFL in certain cases only. patch_binop + knows how to handle those cases. */ + wfl_op1 = TREE_OPERAND (node, 0); + wfl_op2 = TREE_OPERAND (node, 1); + TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + TREE_OPERAND (node, 1) = java_complete_tree (wfl_op2); + if (TREE_OPERAND (node, 1) == error_mark_node) + return error_mark_node; + return patch_binop (node, wfl_op1, wfl_op2); + + case JAVA_UNARY_PLUS_EXPR: + case NEGATE_EXPR: + case TRUTH_NOT_EXPR: + case BIT_NOT_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case CONVERT_EXPR: + /* There are cases were wfl_op1 is a WFL. patch_unaryop knows + how to handle those cases. */ + wfl_op1 = TREE_OPERAND (node, 0); + TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + return patch_unaryop (node, wfl_op1); + + case ARRAY_REF: + /* There are cases were wfl_op1 is a WFL. patch_array_ref knows + how to handle those cases. */ + wfl_op1 = TREE_OPERAND (node, 0); + TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + /* The same applies to wfl_op2 */ + wfl_op2 = TREE_OPERAND (node, 1); + TREE_OPERAND (node, 1) = java_complete_tree (wfl_op2); + if (TREE_OPERAND (node, 1) == error_mark_node) + return error_mark_node; + return patch_array_ref (node, wfl_op1, wfl_op2); + + case JAVA_THIS_EXPR: + /* Can't use THIS in a static environment */ + if (!current_this) + { + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + parse_error_context (wfl_operator, "Keyword `this' used outside " + "allowed context"); + TREE_TYPE (node) = error_mark_node; + return error_mark_node; + } + return current_this; + + case STRING_CST: + /* Build the internal string representation */ + push_obstacks (&permanent_obstack, &permanent_obstack); + node = get_identifier (TREE_STRING_POINTER (node)); + location = alloc_name_constant (CONSTANT_String, node); + node = build_ref_from_constant_pool (location); + TREE_TYPE (node) = promote_type (string_type_node); + return node; + + default: + fatal ("No case for tree code `%s' - java_complete_tree\n", + tree_code_name [TREE_CODE (node)]); + } + return node; +} + +/* Complete function call's argument. Return a non zero value is an + error was found. */ + +static int +complete_function_arguments (node) + tree node; +{ + int flag = 0; + tree cn; + + for (cn = TREE_OPERAND (node, 1); cn; cn = TREE_CHAIN (cn)) + { + tree wfl = TREE_VALUE (cn), parm; + parm = java_complete_tree (wfl); + if (parm == error_mark_node) + { + flag = 1; + continue; + } + if (TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE) + TREE_VALUE (cn) = convert (promote_type (TREE_TYPE (parm)), parm); + else + TREE_VALUE (cn) = save_expr (parm); + if (not_initialized_as_it_should_p (parm)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl, EXPR_WFL_NODE (wfl)); + INITIALIZED_P (parm) = 1; + } + } + return flag; +} + +/* Sometimes (for loops and variable initialized during their + declaration), we want to wrap a statement around a WFL and turn it + debugable. */ + +static tree +build_debugable_stmt (location, stmt) + int location; + tree stmt; +{ + if (TREE_CODE (stmt) != EXPR_WITH_FILE_LOCATION) + { + stmt = build_expr_wfl (stmt, input_filename, 0, 0); + EXPR_WFL_LINECOL (stmt) = location; + } + JAVA_MAYBE_GENERATE_DEBUG_INFO (stmt); + return stmt; +} + +static tree +build_expr_block (body, decls) + tree body, decls; +{ + tree node = make_node (BLOCK); + BLOCK_EXPR_DECLS (node) = decls; + BLOCK_EXPR_BODY (body); + if (body) + TREE_TYPE (node) = TREE_TYPE (body); + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* Create a new function block and link its supercontext to the + previous block. The current function DECL is used as supercontext + when enter_block is called for the first time for a given + function. The current function body (DECL_FUNCTION_BODY) is set to + the newly created block. */ + +static block_level = 0; + +static tree +enter_block () +{ + tree b = build_expr_block (NULL_TREE, NULL_TREE); + tree fndecl = current_function_decl; + + if (!DECL_FUNCTION_BODY (fndecl)) + { + BLOCK_SUPERCONTEXT (b) = fndecl; + DECL_FUNCTION_BODY (fndecl) = b; + } + else + { + BLOCK_SUPERCONTEXT (b) = DECL_FUNCTION_BODY (fndecl); + DECL_FUNCTION_BODY (fndecl) = b; + } + return b; +} + +/* Exit a block by changing the current function body + (DECL_FUNCTION_BODY) to the current block super context, only if + the block being exited isn't the method's top level one. */ + +static tree +exit_block () +{ + tree b = DECL_FUNCTION_BODY (current_function_decl); + + if (BLOCK_SUPERCONTEXT (b) != current_function_decl) + DECL_FUNCTION_BODY (current_function_decl) = BLOCK_SUPERCONTEXT (b); + + return b; +} + +/* Lookup for NAME in the nested function's blocks, all the way up to + the current toplevel one. It complies with Java's local variable + scoping rules. */ + +static tree +lookup_name_in_blocks (name) + tree name; +{ + tree b = DECL_FUNCTION_BODY (current_function_decl); + + while (b != current_function_decl) + { + tree current; + + /* Paranoid sanity check. To be removed */ + if (TREE_CODE (b) != BLOCK) + fatal ("non block expr function body - lookup_name_in_blocks"); + + for (current = BLOCK_EXPR_DECLS (b); current; + current = TREE_CHAIN (current)) + if (DECL_NAME (current) == name) + return current; + b = BLOCK_SUPERCONTEXT (b); + } + return NULL_TREE; +} + +static void +maybe_absorb_scoping_blocks () +{ + while (BLOCK_EXPR_ORIGIN (DECL_FUNCTION_BODY (current_function_decl))) + { + tree b = exit_block (); + java_method_add_stmt (current_function_decl, b); + SOURCE_FRONTEND_DEBUG (("Absorbing scoping block at line %d", lineno)); + } +} + + +/* This section of the source is reserved to build_* functions that + are building incomplete tree nodes and the patch_* functions that + are completing them. */ + +/* Build an incomplete CALL_EXPR node. Encapsulate it within a WFL */ + +static tree +build_method_invocation (name, args) + tree name; + tree args; +{ + tree call = build (CALL_EXPR, NULL_TREE, name, args, NULL_TREE); + TREE_SIDE_EFFECTS (call) = 1; + /* Check on cases where NAME isn't a WFL. FIXME */ + EXPR_WFL_LINECOL (call) = EXPR_WFL_LINECOL (name); + return call; +} + +/* Build an incomplete assignment expression. */ + +static tree +build_assignment (op, op_location, lhs, rhs) + int op, op_location; + tree lhs, rhs; +{ + tree assignment; + /* Build the corresponding binop if we deal with a Compound + Assignment operator. Mark the binop sub-tree as part of a + Compound Assignment expression */ + if (op != ASSIGN_TK) + { + rhs = build_binop (BINOP_LOOKUP (op), op_location, lhs, rhs); + COMPOUND_ASSIGN_P (rhs) = 1; + } + assignment = build (MODIFY_EXPR, NULL_TREE, lhs, rhs); + TREE_SIDE_EFFECTS (assignment) = 1; + EXPR_WFL_LINECOL (assignment) = op_location; + return assignment; +} + +/* Print an INTEGER_CST node in a static buffer, and return the buffer. */ + +static char * +print_int_node (node) + tree node; +{ + static char buffer [80]; + if (TREE_CONSTANT_OVERFLOW (node)) + sprintf (buffer, ""); + + if (TREE_INT_CST_HIGH (node) == 0) + sprintf (buffer, HOST_WIDE_INT_PRINT_UNSIGNED, + TREE_INT_CST_LOW (node)); + else if (TREE_INT_CST_HIGH (node) == -1 + && TREE_INT_CST_LOW (node) != 0) + { + buffer [0] = '-'; + sprintf (&buffer [1], HOST_WIDE_INT_PRINT_UNSIGNED, + -TREE_INT_CST_LOW (node)); + } + else + sprintf (buffer, HOST_WIDE_INT_PRINT_DOUBLE_HEX, + TREE_INT_CST_HIGH (node), TREE_INT_CST_LOW (node)); + + return buffer; +} + +/* 15.25 Assignment operators. */ + +static tree +patch_assignment (node, wfl_op1, wfl_op2) + tree node; + tree wfl_op1; + tree wfl_op2; +{ + tree rhs = TREE_OPERAND (node, 1); + tree lvalue = TREE_OPERAND (node, 0); + tree lhs_type, rhs_type, new_rhs = NULL_TREE; + int all_primitive; + int error_found = 0; + int lvalue_from_array = 0; + + /* Can't assign to a final. */ + if (DECL_P (lvalue) && FIELD_FINAL (lvalue)) + { + parse_error_context + (wfl_op1, "Can't assign a value to the final variable `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl_op1))); + error_found = 1; + } + + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* Lhs can be a named variable */ + if (DECL_P (lvalue)) + { + INITIALIZED_P (lvalue) = 1; + lhs_type = TREE_TYPE (lvalue); + } + /* Or Lhs can be a array acccess. Should that be lvalue ? FIXME + + comment on reason why */ + else if (TREE_CODE (wfl_op1) == ARRAY_REF) + { + lhs_type = TREE_TYPE (lvalue); + lvalue_from_array = 1; + } + /* Or a field access */ + else if (TREE_CODE (lvalue) == COMPONENT_REF) + lhs_type = TREE_TYPE (lvalue); + /* Or a function return slot */ + else if (TREE_CODE (lvalue) == RESULT_DECL) + lhs_type = TREE_TYPE (lvalue); + /* Otherwise, this is an error */ + else + { + parse_error_context (wfl_op1, "Invalid left hand side of assignment"); + error_found = 1; + } + + rhs_type = TREE_TYPE (rhs); + + /* 5.2 Begin Assignment conversion */ + + /* 5.1.1 Try Identity Conversion */ + if (lhs_type == rhs_type) + new_rhs = rhs; + + /* 5.1.2 Try Widening Primitive Conversion */ + all_primitive = JPRIMITIVE_TYPE_P (lhs_type) && JPRIMITIVE_TYPE_P (rhs_type); + if (all_primitive && JINTEGRAL_TYPE_P (rhs_type) + && ((TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type)) + || (JFLOAT_TYPE_P (lhs_type) && + TYPE_PRECISION (rhs_type) == TYPE_PRECISION (lhs_type)))) + new_rhs = convert (lhs_type, rhs); + else if (all_primitive && JFLOAT_TYPE_P (rhs_type) + && (TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type))) + new_rhs = convert (lhs_type, rhs); + + /* Try a narrowing primitive conversion: + - expression is a constant expression of type int AND + - variable is byte, short or char AND + - The value of the expression is representable in the type of the + variable */ + else if (rhs_type == int_type_node && TREE_CONSTANT (rhs) + && (lhs_type == byte_type_node || lhs_type == char_type_node + || lhs_type == short_type_node)) + { + if (int_fits_type_p (rhs, lhs_type)) + new_rhs = convert (lhs_type, rhs); + else + parse_warning_context + (wfl_op1, "Constant expression `%s' to wide for narrowing " + "primitive conversion to `%s'", + print_int_node (rhs), lang_printable_name (lhs_type)); + /* Reported a warning that will turn into an error further + down, so we don't return */ + } + + /* 5.2 Try a reference conversion */ + else if (!JPRIMITIVE_TYPE_P (rhs_type) && JREFERENCE_TYPE_P (lhs_type)) + { + /* `null' may be assigned to any reference type */ + if (rhs == null_pointer_node) + new_rhs = null_pointer_node; + /* Try the reference assignment conversion */ + else if (valid_ref_assignconv_cast_p (rhs_type, lhs_type, 0)) + new_rhs = rhs; + if (new_rhs) + lhs_type = promote_type (rhs_type); + } + + /* 15.25.2 If we have a compound assignment, convert RHS into the + type of the LHS */ + else if (COMPOUND_ASSIGN_P (TREE_OPERAND (node, 1))) + new_rhs = convert (lhs_type, rhs); + + /* Explicit cast required. This is an error */ + if (!new_rhs) + { + char *t1 = strdup ((char *)lang_printable_name (TREE_TYPE (rhs))); + char *t2 = strdup ((char *)lang_printable_name (lhs_type)); + tree wfl; + char operation [32]; /* Max size known */ + + /* If the assignment is part of a declaration, we use the WFL of + the declared variable to point out the error and call it a + declaration problem. If the assignment is a genuine = + operator, we call is a operator `=' problem, otherwise we + call it an assignment problem. In both of these last cases, + we use the WFL of the operator to indicate the error. */ + + if (MODIFY_EXPR_FROM_INITIALIZATION_P (node)) + { + wfl = wfl_op1; + strcpy (operation, "declaration"); + } + else + { + wfl = wfl_operator; + if (COMPOUND_ASSIGN_P (TREE_OPERAND (node, 1))) + strcpy (operation, "assignment"); + else if (TREE_CODE (TREE_OPERAND (node, 0)) == RESULT_DECL) + strcpy (operation, "`return'"); + else + strcpy (operation, "`='"); + } + + parse_error_context + (wfl, (!can_cast_to_p (rhs_type, lhs_type) ? + "Incompatible type for %s. Can't convert `%s' to `%s'" : + "Incompatible type for %s. Explicit cast " + "needed to convert `%s' to `%s'"), operation, t1, t2); + free (t1); free (t2); + error_found = 1; + } + + /* Before reporting type incompatibility errors, check that the rhs + is initialized, if a variable */ + if (not_initialized_as_it_should_p (rhs)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_op2, DECL_NAME (rhs)); + INITIALIZED_P (rhs) = 1; + } + + if (error_found) + return error_mark_node; + + /* If we built a compound expression as the result of a reference + assignment into an array element, return it here. */ + if (TREE_CODE (node) == COMPOUND_EXPR) + return node; + + TREE_OPERAND (node, 0) = lvalue; + TREE_OPERAND (node, 1) = new_rhs; + TREE_TYPE (node) = lhs_type; + return node; +} + +/* Check that SOURCE can be converted into DEST, at least with a + cast. If the convertion can't occur at all, return 0 otherwise + 1. This function is used to produce accurate error messages on the + reasons why an assignment failed. */ + +static int +can_cast_to_p (source, dest) + tree source; + tree dest; +{ + if (TREE_CODE (source) == POINTER_TYPE) + source = TREE_TYPE (source); + if (TREE_CODE (dest) == POINTER_TYPE) + dest = TREE_TYPE (dest); + + if (TREE_CODE (source) == RECORD_TYPE && TREE_CODE (dest) == RECORD_TYPE) + return valid_ref_assignconv_cast_p (source, dest, 1); + + else if (JNUMERIC_TYPE_P (source) && JNUMERIC_TYPE_P (dest)) + return 1; + + return 0; +} + +/* Check that something of SOURCE type can be assigned or cast to + something of DEST type at runtime. Return 1 if the operation is + valid, 0 otherwise. If CAST is set to 1, we're treating the case + were SOURCE is cast into DEST, which borrows a lot of the + assignment check. */ + +static int +valid_ref_assignconv_cast_p (source, dest, cast) + tree source; + tree dest; + int cast; +{ + if (TREE_CODE (source) == POINTER_TYPE) + source = TREE_TYPE (source); + if (TREE_CODE (dest) == POINTER_TYPE) + dest = TREE_TYPE (dest); + /* Case where SOURCE is a class type */ + if (TYPE_CLASS_P (source)) + { + if (TYPE_CLASS_P (dest)) + return source == dest || inherits_from_p (source, dest) + || cast && inherits_from_p (dest, source); + if (TYPE_INTERFACE_P (dest)) + { + /* If doing a cast and SOURCE is final, the operation is + always correct a compile time (because even if SOURCE + does not implement DEST, a subclass of SOURCE might). */ + if (cast && !CLASS_FINAL (TYPE_NAME (source))) + return 1; + /* Otherwise, SOURCE must implement DEST */ + return interface_of_p (dest, source); + } + /* DEST is an array, cast permited if SOURCE is of Object type */ + return (cast && source == object_type_node ? 1 : 0); + } + if (TYPE_INTERFACE_P (source)) + { + if (TYPE_CLASS_P (dest)) + { + /* If not casting, DEST must be the Object type */ + if (!cast) + return dest == object_type_node; + /* We're doing a cast. The cast is always valid is class + DEST is not final, otherwise, DEST must implement SOURCE */ + else if (!CLASS_FINAL (TYPE_NAME (source))) + return 1; + else + return interface_of_p (source, dest); + } + if (TYPE_INTERFACE_P (dest)) + { + /* If doing a cast, then if SOURCE and DEST contain method + with the same signature but different return type, then + this is a (compile time) error */ + if (cast) + { + tree method_source, method_dest; + tree source_type; + tree source_sig, dest_sig; + tree source_name; + for (method_source = TYPE_METHODS (source); method_source; + method_source = TREE_CHAIN (method_source)) + { + source_sig = + build_java_argument_signature (TREE_TYPE (method_source)); + source_type = TREE_TYPE (TREE_TYPE (method_source)); + source_name = DECL_NAME (method_source); + for (method_dest = TYPE_METHODS (dest); + method_dest; method_dest = TREE_CHAIN (method_dest)) + if (source_sig == + build_java_argument_signature (TREE_TYPE (method_dest)) + && source_name == DECL_NAME (method_dest) + && source_type != TREE_TYPE (TREE_TYPE (method_dest))) + return 0; + } + return 1; + } + else + return source == dest || interface_of_p (dest, source); + } + else /* Array */ + return 0; + } + if (TYPE_ARRAY_P (source)) + { + if (TYPE_CLASS_P (dest)) + return dest == object_type_node; + if (TYPE_INTERFACE_P (dest)) + return 0; /* Install test on Clonable. FIXME */ + else /* Arrays */ + { + tree source_element_type = TYPE_ARRAY_ELEMENT (source); + tree dest_element_type = TYPE_ARRAY_ELEMENT (dest); + + if (source_element_type == dest_element_type) + return 1; + return valid_ref_assignconv_cast_p (source_element_type, + dest_element_type, cast); + } + return 0; + } + return 0; +} + +/* Build an incomplete binop expression. */ + +static tree +build_binop (op, op_location, op1, op2) + enum tree_code op; + int op_location; + tree op1, op2; +{ + tree wfl; + + /* URSHIFT_EXPR is not part of what GCC understands, we can't directly build + a node with it */ + tree binop = + build ((op == URSHIFT_EXPR ? RSHIFT_EXPR : op), NULL_TREE, op1, op2); + if (op == URSHIFT_EXPR) + TREE_SET_CODE (binop, op); + + TREE_SIDE_EFFECTS (binop) = 1; + /* Store the location of the operator, for better error report. The + string of the operator will be rebuild based on the OP value. */ + EXPR_WFL_LINECOL (binop) = op_location; + return binop; +} + +/* Build the string of the operator retained by NODE. If NODE is part + of a compound expression, add an '=' at the end of the string. This + function is called when an error needs to be reported on an + operator. The string is returned as a pointer to a static character + buffer. */ + +static char * +operator_string (node) + tree node; +{ +#define BUILD_OPERATOR_STRING(S) \ + { \ + sprintf (buffer, "%s%s", S, (COMPOUND_ASSIGN_P (node) ? "=" : "")); \ + return buffer; \ + } + + static char buffer [10]; + switch (TREE_CODE (node)) + { + case MULT_EXPR: BUILD_OPERATOR_STRING ("*"); + case RDIV_EXPR: BUILD_OPERATOR_STRING ("/"); + case TRUNC_MOD_EXPR: BUILD_OPERATOR_STRING ("%"); + case PLUS_EXPR: BUILD_OPERATOR_STRING ("+"); + case MINUS_EXPR: BUILD_OPERATOR_STRING ("-"); + case LSHIFT_EXPR: BUILD_OPERATOR_STRING ("<<"); + case RSHIFT_EXPR: BUILD_OPERATOR_STRING (">>"); + case URSHIFT_EXPR: BUILD_OPERATOR_STRING (">>>"); + case BIT_AND_EXPR: BUILD_OPERATOR_STRING ("&"); + case BIT_XOR_EXPR: BUILD_OPERATOR_STRING ("^"); + case BIT_IOR_EXPR: BUILD_OPERATOR_STRING ("|"); + case TRUTH_ANDIF_EXPR: BUILD_OPERATOR_STRING ("&&"); + case TRUTH_ORIF_EXPR: BUILD_OPERATOR_STRING ("||"); + case EQ_EXPR: BUILD_OPERATOR_STRING ("=="); + case NE_EXPR: BUILD_OPERATOR_STRING ("!="); + case GT_EXPR: BUILD_OPERATOR_STRING (">"); + case GE_EXPR: BUILD_OPERATOR_STRING (">="); + case LT_EXPR: BUILD_OPERATOR_STRING ("<"); + case LE_EXPR: BUILD_OPERATOR_STRING ("<="); + case JAVA_UNARY_PLUS_EXPR: BUILD_OPERATOR_STRING ("+"); + case NEGATE_EXPR: BUILD_OPERATOR_STRING ("-"); + case TRUTH_NOT_EXPR: BUILD_OPERATOR_STRING ("!"); + case BIT_NOT_EXPR: BUILD_OPERATOR_STRING ("~"); + case PREINCREMENT_EXPR: /* Fall through */ + case POSTINCREMENT_EXPR: BUILD_OPERATOR_STRING ("++"); + case PREDECREMENT_EXPR: /* Fall through */ + case POSTDECREMENT_EXPR: BUILD_OPERATOR_STRING ("--"); + default: + fatal ("unregistered operator %s - operator_string", + tree_code_name [TREE_CODE (node)]); + } + return NULL; +#undef BUILD_OPERATOR_STRING +} + +/* Binary operators (15.16 up to 15.18). We return error_mark_node on + errors but we modify NODE so that it contains the type computed + according to the expression, when it's fixed. Otherwise, we write + error_mark_node as the type. It allows us to further the analysis + of remaining nodes and detects more errors in certain cases. */ + +static tree +patch_binop (node, wfl_op1, wfl_op2) + tree node; + tree wfl_op1; + tree wfl_op2; +{ + tree op1 = TREE_OPERAND (node, 0); + tree op2 = TREE_OPERAND (node, 1); + tree op1_type = TREE_TYPE (op1); + tree op2_type = TREE_TYPE (op2); + tree prom_type; + int code = TREE_CODE (node); + /* If 1, tell the routine that we have to return error_mark_node + after checking for the initialization of the RHS */ + int error_found = 0; + + /* Figure what is going to be checked first for initialization prior + its use. If NODE is part of a compound assignment, we check the + second operand first, otherwise the first one first. We also + initialize the matching WFL for the error report. `cfi' stands + for Check For Initialization */ + tree cfi = (COMPOUND_ASSIGN_P (node) ? op2 : op1); + tree cfi_wfl = (COMPOUND_ASSIGN_P (node) ? wfl_op2 : wfl_op1); + + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* Check initialization of LHS first. We then silence further error + message if the variable wasn't initialized */ + if (not_initialized_as_it_should_p (cfi)) + { + ERROR_VARIABLE_NOT_INITIALIZED (cfi_wfl, DECL_NAME (cfi)); + INITIALIZED_P (op1) = 1; + } + + switch (code) + { + /* 15.16 Multiplicative operators */ + case MULT_EXPR: /* 15.16.1 Multiplication Operator * */ + case RDIV_EXPR: /* 15.16.2 Division Operator / */ + case TRUNC_MOD_EXPR: /* 15.16.3 Remainder operator % */ + if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type)) + { + if (!JPRIMITIVE_TYPE_P (op1_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op1_type); + if (!JPRIMITIVE_TYPE_P (op2_type) && (op1_type != op2_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op2_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + break; + } + prom_type = binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + /* Change the division operator if necessary */ + if (code == RDIV_EXPR && TREE_CODE (prom_type) == INTEGER_TYPE) + TREE_SET_CODE (node, TRUNC_DIV_EXPR); + /* This one is more complicated. FLOATs are processed by a function + call to soft_fmod. */ + if (code == TRUNC_MOD_EXPR) + return build_java_binop (TRUNC_MOD_EXPR, prom_type, op1, op2); + break; + + /* 15.17 Additive Operators */ + case PLUS_EXPR: /* 15.17.1 String Concatenation Operator + */ + if (JSTRING_TYPE_P (op1_type) || JSTRING_TYPE_P (op2_type)) + fatal ("operator `+' non implemented on String - patch_binop"); + case MINUS_EXPR: /* 15.17.2 Additive Operators (+ and -) for + Numeric Types */ + if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type)) + { + if (!JPRIMITIVE_TYPE_P (op1_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op1_type); + if (!JPRIMITIVE_TYPE_P (op2_type) && (op1_type != op2_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op2_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + break; + } + prom_type = binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + break; + + /* 15.18 Shift Operators */ + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case URSHIFT_EXPR: + if (!JINTEGRAL_TYPE_P (op1_type) || !JINTEGRAL_TYPE_P (op2_type)) + { + if (!JINTEGRAL_TYPE_P (op1_type)) + ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op1_type); + else + parse_error_context + (wfl_operator, (JPRIMITIVE_TYPE_P (op2_type) ? + "Incompatible type for `%s'. Explicit cast needed to convert " + "shift distance from `%s' to integral" : + "Incompatible type for `%s'. Can't convert shift distance from " + "`%s' to integral"), + operator_string (node), lang_printable_name (op2_type)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + break; + } + + /* Unary numeric promotion (5.6.1) is performed on each operand + separatly */ + op1 = convert (promote_type (op1_type), op1); + op2 = convert (promote_type (op2_type), op2); + + /* The type of the shift expression is the type of the promoted + type of the left-hand operand */ + prom_type = TREE_TYPE (op1); + + /* Shift int only up to 0x1f and long up to 0x3f */ + if (prom_type == int_type_node) + op2 = fold (build (BIT_AND_EXPR, int_type_node, op2, + build_int_2 (0x1f, 0))); + else + op2 = fold (build (BIT_AND_EXPR, int_type_node, op2, + build_int_2 (0x3f, 0))); + + /* The >>> operator is a >> operating on unsigned quantities */ + if (code == URSHIFT_EXPR) + { + op1 = convert (unsigned_type (prom_type), op1); + TREE_SET_CODE (node, RSHIFT_EXPR); + } + break; + + + /* 15.21 Bitwise and Logical Operators */ + case BIT_AND_EXPR: + case BIT_XOR_EXPR: + case BIT_IOR_EXPR: + if (JINTEGRAL_TYPE_P (op1_type) && JINTEGRAL_TYPE_P (op2_type)) + /* Binary numeric promotion is performed on both operand and the + expression retain that type */ + prom_type = binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + + else if (TREE_CODE (op1_type) == BOOLEAN_TYPE + && TREE_CODE (op1_type) == BOOLEAN_TYPE) + /* The type of the bitwise operator expression is BOOLEAN */ + prom_type = boolean_type_node; + else + { + if (!JINTEGRAL_TYPE_P (op1_type)) + ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op1_type); + if (!JINTEGRAL_TYPE_P (op2_type) && (op1_type != op2_type)) + ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op2_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + /* Insert a break here if adding thing before the switch's + break for this case */ + } + break; + + /* 15.22 Conditional-And Operator */ + case TRUTH_ANDIF_EXPR: + /* 15.23 Conditional-Or Operator */ + case TRUTH_ORIF_EXPR: + /* Operands must be of BOOLEAN type */ + if (TREE_CODE (op1_type) != BOOLEAN_TYPE || + TREE_CODE (op2_type) != BOOLEAN_TYPE) + { + if (TREE_CODE (op1_type) != BOOLEAN_TYPE) + ERROR_CANT_CONVERT_TO_BOOLEAN (wfl_operator, node, op1_type); + if (TREE_CODE (op2_type) != BOOLEAN_TYPE && (op1_type != op2_type)) + ERROR_CANT_CONVERT_TO_BOOLEAN (wfl_operator, node, op2_type); + TREE_TYPE (node) = boolean_type_node; + error_found = 1; + break; + } + /* The type of the conditional operators is BOOLEAN */ + prom_type = boolean_type_node; + break; + + /* 15.19.1 Numerical Comparison Operators <, <=, >, >= */ + case LT_EXPR: + case GT_EXPR: + case LE_EXPR: + case GE_EXPR: + /* The type of each of the operands must be a primitive numeric + type */ + if (!JNUMERIC_TYPE_P (op1_type) || ! JNUMERIC_TYPE_P (op2_type)) + { + if (!JNUMERIC_TYPE_P (op1_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op1_type); + if (!JNUMERIC_TYPE_P (op2_type) && (op1_type != op2_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op2_type); + TREE_TYPE (node) = boolean_type_node; + error_found = 1; + break; + } + /* Binary numeric promotion is performed on the operands */ + binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + /* The type of the relation expression is always BOOLEAN */ + prom_type = boolean_type_node; + break; + + /* 15.20 Equality Operator */ + case EQ_EXPR: + case NE_EXPR: + /* 15.20.1 Numerical Equality Operators == and != */ + /* Binary numeric promotion is performed on the operands */ + if (JPRIMITIVE_TYPE_P (op1_type) && JPRIMITIVE_TYPE_P (op2_type)) + binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + + /* 15.20.2 Boolean Equality Operators == and != */ + else if (TREE_CODE (op1_type) == BOOLEAN_TYPE && + TREE_CODE (op2_type) == BOOLEAN_TYPE) + ; /* Nothing to do here */ + + /* 15.20.3 Reference Equality Operators == and != */ + /* Types have to be either references or the null type */ + else if ((op1 == null_pointer_node || op2 == null_pointer_node + || JREFERENCE_TYPE_P (op1_type) + || JREFERENCE_TYPE_P (op2_type)) + && ((op1_type == op2_type) + /* The should use a can_cast_to_p() */ + )) + ; /* Nothing to do here */ + + /* Else we have an error figure what can't be converted into + what and report the error */ + else + { + char *t1; + t1 = strdup ((char *)lang_printable_name (op1_type)); + parse_error_context + (wfl_operator, "Incompatible type for `%s'. Can't convert `%s' " + "to `%s'", operator_string (node), t1, + lang_printable_name (op2_type)); + free (t1); + TREE_TYPE (node) = boolean_type_node; + error_found = 1; + break; + } + prom_type = boolean_type_node; + break; + } + + /* Then check the initialization of the RHS. We don't do that if + we're dealing with a node that is part of a compound + assignment. We then silence further error message if the variable + wasn't initialized */ + if (not_initialized_as_it_should_p (op2) && !COMPOUND_ASSIGN_P (node)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_op2, DECL_NAME (op2)); + INITIALIZED_P (op2) = 1; + } + + if (error_found) + return error_mark_node; + + TREE_OPERAND (node, 0) = op1; + TREE_OPERAND (node, 1) = op2; + TREE_TYPE (node) = prom_type; + return fold (node); +} + +/* Build an incomplete unary operator expression. Unary `+' node is + build as a CONV_EXPR, even though its tree code is overridden by a + JAVA_UNARY_PLUS_EXPR that isn't a tree code, to differentiate it during + the walk. */ + +static tree +build_unaryop (op_token, op_location, op1) + int op_token, op_location; + tree op1; +{ + enum tree_code op; + tree unaryop; + switch (op_token) + { + case PLUS_TK: op = CONVERT_EXPR; break; + case MINUS_TK: op = NEGATE_EXPR; break; + case NEG_TK: op = TRUTH_NOT_EXPR; break; + case NOT_TK: op = BIT_NOT_EXPR; break; + default: fatal ("Unknown token `%d' for unary operator - build_unaryop", + op_token); + } + + unaryop = build1 (op, NULL_TREE, op1); + if (op_token == PLUS_TK) + TREE_SET_CODE (unaryop, JAVA_UNARY_PLUS_EXPR); + + TREE_SIDE_EFFECTS (unaryop) = 1; + /* Store the location of the operator, for better error report. The + string of the operator will be rebuild based on the OP value. */ + EXPR_WFL_LINECOL (unaryop) = op_location; + return unaryop; +} + +/* Special case for the ++/-- operators, since they require an extra + argument to build, which is set to NULL and patched + later. IS_POST_P is 1 if the operator, 0 otherwise. */ + +static tree +build_incdec (op_token, op_location, op1, is_post_p) + int op_token, op_location; + tree op1; + int is_post_p; +{ + static enum tree_code lookup [2][2] = + { + { PREDECREMENT_EXPR, PREINCREMENT_EXPR, }, + { POSTDECREMENT_EXPR, POSTINCREMENT_EXPR, }, + }; + tree node = build (lookup [is_post_p][(op_token - DECR_TK)], + NULL_TREE, op1, NULL_TREE); + TREE_SIDE_EFFECTS (node) = 1; + /* Store the location of the operator, for better error report. The + string of the operator will be rebuild based on the OP value. */ + EXPR_WFL_LINECOL (node) = op_location; + return node; +} + +/* Build an incomplete cast operator, based on the use of the + CONVERT_EXPR. Note that TREE_TYPE of the constructed node is + set. java_complete_tree is trained to walk a CONVERT_EXPR even + though its type is already set. */ + +static tree +build_cast (location, type, exp) + int location; + tree type, exp; +{ + tree node = build1 (CONVERT_EXPR, type, exp); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +/* 15.14 Unary operators. We return error_mark_node in case of error, + but preserve the type of NODE if the type is fixed. */ + +static tree +patch_unaryop (node, wfl_op) + tree node; + tree wfl_op; +{ + tree op = TREE_OPERAND (node, 0); + tree op_type = TREE_TYPE (op); + tree prom_type, value; + int code = TREE_CODE (node); + int error_found = 0; + + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + switch (code) + { + /* 15.13.2 Postfix Increment Operator ++ */ + case POSTINCREMENT_EXPR: + /* 15.13.3 Postfix Increment Operator -- */ + case POSTDECREMENT_EXPR: + /* 15.14.1 Prefix Increment Operator ++ */ + case PREINCREMENT_EXPR: + /* 15.14.2 Prefix Decrement Operator -- */ + case PREDECREMENT_EXPR: + if (!DECL_P (op)) + { + parse_error_context (wfl_operator, "Invalid argument to `%s'", + operator_string (node)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + else if (FIELD_FINAL (op)) + { + parse_error_context + (wfl_op, "Can't assign a value to the final variable `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl_op))); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + /* From now on, we know that op if a variable and that it has a + valid wfl. We use wfl_op to locate errors related to the + ++/-- operand. */ + else if (!JNUMERIC_TYPE_P (op_type)) + { + parse_error_context + (wfl_op, "Invalid argument type `%s' to `%s'", + lang_printable_name (op_type), operator_string (node)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + else + { + /* Before the addition, binary numeric promotion if performed on + both operands */ + value = integer_one_node; + prom_type = binary_numeric_promotion (op_type, TREE_TYPE (value), + &op, &value); + /* And write the promoted increment back */ + TREE_OPERAND (node, 1) = value; + } + break; + + /* 15.14.3 Unary Plus Operator + */ + case JAVA_UNARY_PLUS_EXPR: + /* 15.14.4 Unary Minus Operator - */ + case NEGATE_EXPR: + if (!JNUMERIC_TYPE_P (op_type)) + { + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + /* Unary numeric promotion is performed on operand */ + else + { + prom_type = promote_type (op_type); + op = convert (prom_type, op); + if (code == JAVA_UNARY_PLUS_EXPR) + node = op; + } + break; + + /* 15.14.5 Bitwise Complement Operator ~ */ + case BIT_NOT_EXPR: + if (!JINTEGRAL_TYPE_P (op_type)) + { + ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + else + { + prom_type = promote_type (op_type); + op = convert (prom_type, op); + } + break; + + /* 15.14.6 Logical Complement Operator ! */ + case TRUTH_NOT_EXPR: + if (TREE_CODE (op_type) != BOOLEAN_TYPE) + { + ERROR_CANT_CONVERT_TO_BOOLEAN (wfl_operator, node, op_type); + TREE_TYPE (node) = boolean_type_node; + error_found = 1; + } + else + prom_type = boolean_type_node; + break; + + /* 15.15 Cast Expression */ + case CONVERT_EXPR: + value = patch_cast (node, wfl_op, wfl_operator); + if (value == error_mark_node) + { + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + else + node = value; + break; + } + + /* Check variable initialization */ + if (not_initialized_as_it_should_p (op)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_op, DECL_NAME (op)); + INITIALIZED_P (op) = 1; + } + + if (error_found) + return error_mark_node; + /* In the case of JAVA_UNARY_PLUS_EXPR, we replaced NODE by a new one */ + else if (code != JAVA_UNARY_PLUS_EXPR && code != CONVERT_EXPR) + { + TREE_OPERAND (node, 0) = op; + TREE_TYPE (node) = prom_type; + } + return fold (node); +} + +/* Generic type resolution that sometimes takes place during node + patching. Returned the resolved type or generate an error + message. Return the resolved type or NULL_TREE. */ + +static tree +resolve_type_during_patch (type) + tree type; +{ + if (unresolved_type_p (type, NULL)) + { + tree type_decl = resolve_no_layout (EXPR_WFL_NODE (type), NULL_TREE); + if (!type_decl) + { + parse_error_context (type, + "Class `%s' not found in type declaration", + IDENTIFIER_POINTER (EXPR_WFL_NODE (type))); + return NULL_TREE; + } + else + return TREE_TYPE (type_decl); + } + return type; +} +/* 5.5 Casting Conversion. error_mark_node is returned if an error is + found. Otherwise NODE or something meant to replace it is returned. */ + +static tree +patch_cast (node, wfl_op, wfl_operator) + tree node; + tree wfl_op; + tree wfl_operator; +{ + tree op = TREE_OPERAND (node, 0); + tree op_type = TREE_TYPE (op); + tree cast_type = TREE_TYPE (node); + char *t1; + + /* First resolve OP_TYPE if unresolved */ + if (!(cast_type = resolve_type_during_patch (cast_type))) + return error_mark_node; + + /* Check on cast that are proven correct at compile time */ + if (JNUMERIC_TYPE_P (cast_type) && JNUMERIC_TYPE_P (op_type)) + { + static tree convert_narrow (); + /* Same type */ + if (cast_type == op_type) + return node; + + /* Try widening/narowwing convertion. Potentially, things need + to be worked out in gcc so we implement the extreme cases + correctly. fold_convert() needs to be fixed. */ + return convert (cast_type, op); + } + + /* The remaining legal casts involve conversion between reference + types. Check for their compile time correctness. */ + if (JREFERENCE_TYPE_P (op_type) && JREFERENCE_TYPE_P (cast_type) + && valid_ref_assignconv_cast_p (op_type, cast_type, 1)) + { + TREE_TYPE (node) = promote_type (cast_type); + /* Now, the case can be determined correct at compile time if + OP_TYPE can be converted into CAST_TYPE by assignment + conversion (5.2) */ + + if (valid_ref_assignconv_cast_p (op_type, cast_type, 0)) + return node; + + /* The cast requires a run-time check */ + return build (CALL_EXPR, promote_type (cast_type), + build_address_of (soft_checkcast_node), + tree_cons (NULL_TREE, build_class_ref (cast_type), + build_tree_list (NULL_TREE, op)), + NULL_TREE); + } + + /* Any other casts are proven incorrect at compile time */ + t1 = strdup ((char *)lang_printable_name (op_type)); + parse_error_context (wfl_operator, "Invalid cast from `%s' to `%s'", + t1, lang_printable_name (cast_type)); + free (t1); + return error_mark_node; +} + +/* Build an ARRAY_REF incomplete tree node. Note that operand 1 isn't + a list of indices. */ +static tree +build_array_ref (location, array, index) + int location; + tree array, index; +{ + tree node = build (ARRAY_REF, NULL_TREE, array, index); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +/* 15.12 Array Access Expression */ + +static tree +patch_array_ref (node, wfl_array, wfl_index) + tree node, wfl_array, wfl_index; +{ + tree array = TREE_OPERAND (node, 0); + tree array_type = TREE_TYPE (array); + tree index = TREE_OPERAND (node, 1); + tree index_type = TREE_TYPE (index); + tree promoted_index_type; + int error_found = 0; + + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + if (not_initialized_as_it_should_p (array)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_array, DECL_NAME (array)); + INITIALIZED_P (array) = 1; + } + if (! flag_emit_class_files) + array = save_expr (array); + + if (TREE_CODE (array_type) == POINTER_TYPE) + array_type = TREE_TYPE (array_type); + + /* The array reference must be an array */ + if (!TYPE_ARRAY_P (array_type)) + { + parse_error_context + (wfl_operator, "`[]' can only be applied to arrays. It can't be " + "applied to `%s'", lang_printable_name (array_type)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + + /* The array index underdoes unary numeric promotion. The promoted + type must be int */ + promoted_index_type = promote_type (index_type); + if (promoted_index_type != int_type_node) + { + int could_cast = can_cast_to_p (index_type, int_type_node); + parse_error_context + (wfl_operator, + (could_cast ? "Incompatible type for `[]'. Explicit cast needed to " + "convert `%s' to `int'" : "Incompatible type for `[]'. " + "Can't convert `%s' to `int'"), + lang_printable_name (index_type)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + + /* Now if the index is a var/parm decl, check on its initialization */ + if (not_initialized_as_it_should_p (index)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_index, DECL_NAME (index)); + INITIALIZED_P (index) = 1; + } + + if (error_found) + return error_mark_node; + index = convert (promoted_index_type, index); + + if (TREE_CODE (array_type) == RECORD_TYPE) + array_type = promote_type (TYPE_ARRAY_ELEMENT (array_type)); + if (flag_emit_class_files) + { + TREE_OPERAND (node, 0)= array; + TREE_OPERAND (node, 1)= index; + } + else + node = build_java_arrayaccess (array, array_type, index); + TREE_TYPE (node) = array_type; + return node; +} + +/* 15.9 Array Creation Expressions */ + +static tree +build_newarray_node (type, dims, extra_dims) + tree type; + tree dims; + int extra_dims; +{ + tree node = + build (CALL_EXPR, NULL_TREE, type, nreverse (dims), + build_int_2 (extra_dims, 0)); + TREE_SET_CODE (node, JAVA_NEW_ARRAY_EXPR); + return node; +} + +static tree +patch_newarray (node) + tree node; +{ + tree type = TREE_OPERAND (node, 0); + tree dims = TREE_OPERAND (node, 1); + tree cdim, array_type; + int error_found = 0; + int ndims = 0; + int xdims = TREE_INT_CST_LOW (TREE_OPERAND (node, 2)); + int total_dims; + + /* Dimension types are verified. It's better for the types to be + verified in order. */ + for (cdim = dims, ndims = 0; cdim; cdim = TREE_CHAIN (cdim), ndims++ ) + { + int dim_error = 0; + tree dim = TREE_VALUE (cdim); + + /* Dim might have been saved during its evaluation */ + dim = (TREE_CODE (dim) == SAVE_EXPR ? dim = TREE_OPERAND (dim, 0) : dim); + + /* The type of each specified dimension must be an integral type. */ + if (!JINTEGRAL_TYPE_P (TREE_TYPE (dim))) + dim_error = 1; + + /* Each expression undergoes an unary numeric promotion (5.6.1) and the + promoted type must be int. */ + else + { + dim = convert (promote_type (TREE_TYPE (dim)), dim); + if (TREE_TYPE (dim) != int_type_node) + dim_error = 1; + } + + /* Report errors on types here */ + if (dim_error) + { + parse_error_context + (TREE_PURPOSE (cdim), + "Incompatible type for dimension in array creation expression. " + "%s convert `%s' to `int'", + (can_cast_to_p (TREE_TYPE (dim), int_type_node) ? + "Explicit cast needed to" : "Can't"), + lang_printable_name (TREE_TYPE (dim))); + error_found = 1; + } + + /* Check for uninitialized variables */ + if (not_initialized_as_it_should_p (dim)) + { + ERROR_VARIABLE_NOT_INITIALIZED (TREE_PURPOSE (cdim), + DECL_NAME (dim)); + INITIALIZED_P (dim) = 1; + error_found = 1; + } + + TREE_PURPOSE (cdim) = NULL_TREE; + } + + /* Resolve array base type if unresolved */ + if (!(type = resolve_type_during_patch (type))) + error_found = 1; + + if (error_found) + { + /* We don't want further evaluation of this bogus array creation + operation */ + TREE_TYPE (node) = error_mark_node; + return error_mark_node; + } + + /* The node is transformed into a function call. Things are done + differently according to the number of dimensions. If the number + of dimension is equal to 1, then the nature of the base type + (primitive or not) matters. */ + total_dims = xdims + ndims; + if (total_dims == 1) + { + if (JPRIMITIVE_TYPE_P (type)) + { + int type_code; + if (type == boolean_type_node) + type_code = 4; + else if (type == char_type_node) + type_code = 5; + else if (type == float_type_node) + type_code = 6; + else if (type == double_type_node) + type_code = 7; + else if (type == byte_type_node) + type_code = 8; + else if (type == short_type_node) + type_code = 9; + else if (type == int_type_node) + type_code = 10; + else if (type == long_type_node) + type_code = 11; + else + fatal ("Can't compute type code - patch_newarray"); + return build_newarray (type_code, TREE_VALUE (dims)); + } + else + return build_anewarray (type, TREE_VALUE (dims)); + } + + /* Add extra dimensions as unknown dimensions */ + while (xdims--) + dims = + chainon (dims, build_tree_list (NULL_TREE, integer_negative_one_node)); + dims = chainon (dims, build_tree_list (NULL_TREE, integer_zero_node)); + + /* Can't reuse what's already written in expr.c because it uses the + JVM stack representation. Provide a build_multianewarray. FIXME */ + array_type = type; + for (cdim = TREE_CHAIN (dims); cdim; cdim = TREE_CHAIN (cdim)) + array_type = build_java_array_type (promote_type (array_type), + TREE_CODE (cdim) == INTEGER_CST ? + TREE_INT_CST_LOW (cdim) : -1); + return build (CALL_EXPR, + promote_type (array_type), + build_address_of (soft_multianewarray_node), + tree_cons (NULL_TREE, build_class_ref (array_type), + tree_cons (NULL_TREE, + build_int_2 (total_dims, 0), dims )), + NULL_TREE); +} + +static tree +build_this (location) + int location; +{ + tree node = build_wfl_node (this_identifier_node, input_filename, 0, 0); + TREE_SET_CODE (node, JAVA_THIS_EXPR); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +/* 14.15 The return statement. It builds a modify expression that + assigns the returned value to the RESULT_DECL that hold the value + to be returned. */ + +static tree +build_return (location, op) + int location; + tree op; +{ + tree node = build1 (RETURN_EXPR, NULL_TREE, op); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +static tree +patch_return (node) + tree node; +{ + tree return_exp = TREE_OPERAND (node, 0); + tree meth = current_function_decl; + tree mtype = TREE_TYPE (TREE_TYPE (current_function_decl)); + tree modify; + int error_found = 0; + + TREE_TYPE (node) = error_mark_node; + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* It's invalid to have a return value within a function that is + declared with the keyword void or that is a constructor */ + if (return_exp && (mtype == void_type_node || DECL_CONSTRUCTOR_P (meth))) + error_found = 1; + + /* It's invalid to have a no return value within a function that + isn't declared with the keyword `void' */ + if (!return_exp && (mtype != void_type_node && !DECL_CONSTRUCTOR_P (meth))) + error_found = 2; + + if (error_found) + { + char *t = strdup ((char *)lang_printable_name (mtype)); + parse_error_context (wfl_operator, "`return' with%s value from `%s %s'", + (error_found == 1 ? "" : "out"), t, + lang_printable_name (meth)); + free (t); + return error_mark_node; + } + + /* If we have a return_exp, build a modify expression and expand it */ + if (return_exp) + { + modify = build (MODIFY_EXPR, NULL_TREE, DECL_RESULT (meth), return_exp); + EXPR_WFL_LINECOL (modify) = EXPR_WFL_LINECOL (node); + modify = java_complete_tree (modify); + if (modify != error_mark_node) + { + TREE_SIDE_EFFECTS (modify) = 1; + TREE_OPERAND (node, 0) = modify; + } + else + return error_mark_node; + } + TREE_TYPE (node) = void_type_node; + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* 14.8 The if Statement */ + +static tree +build_if_else_statement (location, expression, if_body, else_body) + int location; + tree expression, if_body, else_body; +{ + tree node; + /* FIXME: make else body be a void node, where this function is + called */ + if (!else_body) + else_body = build (COMPOUND_EXPR, void_type_node, NULL_TREE, NULL_TREE); + node = build (COND_EXPR, NULL_TREE, expression, if_body, else_body); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +static tree +patch_if_else_statement (node) + tree node; +{ + tree expression = TREE_OPERAND (node, 0); + + TREE_TYPE (node) = error_mark_node; + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* The type of expression must be boolean */ + if (TREE_TYPE (expression) != boolean_type_node) + { + parse_error_context + (wfl_operator, + "Incompatible type for `if'. Can't convert `%s' to `boolean'", + lang_printable_name (TREE_TYPE (expression))); + return error_mark_node; + } + + TREE_TYPE (node) = void_type_node; + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* 14.6 Labeled Statements */ + +/* Action taken when a lableled statement is parsed. a new + LABELED_BLOCK_EXPR is created. No statement is attached to the + label, yet. */ + +static tree +build_labeled_block (location, label, wfl) + int location; + tree label, wfl; +{ + tree label_name = merge_qualified_name (label_id, label); + tree label_decl, node; + + /* Issue a warning if we try to reuse a label that was previously + declared */ + if (IDENTIFIER_LOCAL_VALUE (label_name)) + { + EXPR_WFL_LINECOL (wfl_operator) = location; + parse_warning_context (wfl_operator, "Declaration of `%s' shadows " + "a previous declaration", + IDENTIFIER_POINTER (label)); + EXPR_WFL_LINECOL (wfl_operator) = + EXPR_WFL_LINECOL (IDENTIFIER_LOCAL_VALUE (label_name)); + parse_warning_context (wfl_operator, "This is the location of the " + "previous declaration of label `%s'", + IDENTIFIER_POINTER (label)); + java_warning_count--; + } + + label_decl = create_label_decl (label_name); + node = build (LABELED_BLOCK_EXPR, NULL_TREE, label_decl, NULL_TREE); + EXPR_WFL_LINECOL (node) = location; + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* Generate a label crafting a unique name for it. This is used to + implicitely label loops that aren't the body part of labeled + statement. */ + +static tree +generate_labeled_block () +{ + static int l_number = 0; + char buf [20]; + tree label_name; + + sprintf (buf, "$a%d", l_number++); + return build_labeled_block (0, get_identifier (buf), NULL_TREE); +} + +/* A labeled statement LBE is attached a statement. If the statement + happens to be a loop, a link from the loop back to the label is + installed. */ + +static tree +complete_labeled_statement (lbe, statement) + tree lbe; /* Labeled block expr */ + tree statement; +{ + /* In anyways, tie the loop to its statement */ + LABELED_BLOCK_BODY (lbe) = statement; + + /* Ok, if statement is a for loop, we have to attach the labeled + statement to the block the for loop belongs to and return the + block instead */ + if (TREE_CODE (statement) == LOOP_EXPR && IS_FOR_LOOP_P (statement)) + { + java_method_add_stmt (current_function_decl, lbe); + return exit_block (); + } + + return lbe; +} + +/* 14.10, 14.11, 14.12 Loop Statements */ + +/* Create an empty LOOP_EXPR and make it the last in the nested loop + list. */ + +static tree +build_new_loop (loop_body) + tree loop_body; +{ + tree loop = build (LOOP_EXPR, NULL_TREE, loop_body); + TREE_SIDE_EFFECTS (loop) = 1; + PUSH_LOOP (loop); + return loop; +} + +/* Create a loop body according to the following structure: + COMPOUND_EXPR + COMPOUND_EXPR (loop main body) + EXIT_EXPR (this order is for while/for loops. + LABELED_BLOCK_EXPR the order is reversed for do loops) + LABEL_DECL (continue occurding here branche at the + BODY end of this labeled block) + INCREMENT (if any) + + REVERSED, if non zero, tells that the loop condition expr comes + after the body, like in the do-while loop. */ + +static tree +build_loop_body (location, condition, reversed) + int location; + tree condition; + int reversed; +{ + tree first, second, label, body; + + condition = build (EXIT_EXPR, NULL_TREE, condition); /* Force walk */ + EXPR_WFL_LINECOL (condition) = location; /* For accurate error report */ + condition = build_debugable_stmt (location, condition); + TREE_SIDE_EFFECTS (condition) = 1; + + body = generate_labeled_block (); + first = (reversed ? body : condition); + second = (reversed ? condition : body); + return + build (COMPOUND_EXPR, NULL_TREE, + build (COMPOUND_EXPR, NULL_TREE, first, second), size_zero_node); +} + +/* Install CONDITION (if any) and loop BODY (using REVERSED to tell + their order) on the current loop. Unlink the current loop from the + loop list. */ + +static tree +complete_loop_body (location, condition, body, reversed) + int location; + tree condition, body; + int reversed; +{ + tree to_return = ctxp->current_loop; + tree loop_body = LOOP_EXPR_BODY (to_return); + if (condition) + { + tree cnode = LOOP_EXPR_BODY_CONDITION_EXPR (loop_body, reversed); + /* We wrapped the EXIT_EXPR around a WFL so we can debug it. + The real EXIT_EXPR is one operand further. */ + EXPR_WFL_LINECOL (cnode) = location; + /* This one is for accurate error reports */ + EXPR_WFL_LINECOL (TREE_OPERAND (cnode, 0)) = location; + TREE_OPERAND (TREE_OPERAND (cnode, 0), 0) = condition; + } + LOOP_EXPR_BODY_BODY_EXPR (loop_body, reversed) = body; + POP_LOOP (); + return to_return; +} + +/* Tailored version of complete_loop_body for FOR loops, when FOR + loops feature the condition part */ + +static tree +complete_for_loop (location, condition, update, body) + int location; + tree condition, update, body; +{ + /* Put the condition and the loop body in place */ + tree loop = complete_loop_body (location, condition, body, 0); + /* LOOP is the current loop which has been now popped of the loop + stack. Install the update block */ + LOOP_EXPR_BODY_UPDATE_BLOCK (LOOP_EXPR_BODY (loop)) = update; + return loop; +} + +/* If the loop isn't surrounded by a labeled statement, create one and + insert LOOP as it's body. */ + +static tree +patch_loop_statement (loop) + tree loop; +{ + tree cbl, loop_label, to_return_as_loop; + + if (LOOP_HAS_LABEL_P (loop)) + { + loop_label = ctxp->current_labeled_block; + to_return_as_loop = loop; + } + else + { + loop_label = generate_labeled_block (); + LABELED_BLOCK_BODY (loop_label) = loop; + PUSH_LABELED_BLOCK (loop_label); + to_return_as_loop = loop_label; + } + TREE_TYPE (to_return_as_loop) = void_type_node; + return to_return_as_loop; +} + +/* 14.13, 14.14: break and continue Statements */ + +/* Build a break or a continue statement. a null NAME indicates an + unlabeled break/continue statement. */ + +static tree +build_bc_statement (location, is_break, name) + int location, is_break; + tree name; +{ + tree break_continue, label_block_expr = NULL_TREE; + + if (name) + { + if (!(label_block_expr = IDENTIFIER_LOCAL_VALUE + (merge_qualified_name (label_id, EXPR_WFL_NODE (name))))) + /* Null means that we don't have a target for this named + break/continue. In this case, we make the target to be the + label name, so that the error can be reported accuratly in + patch_bc_statement. */ + label_block_expr = EXPR_WFL_NODE (name); + } + /* Unlabeled break/continue will be handled during the + break/continue patch operation */ + break_continue + = build (EXIT_BLOCK_EXPR, NULL_TREE, label_block_expr, NULL_TREE); + + IS_BREAK_STMT_P (break_continue) = is_break; + TREE_SIDE_EFFECTS (break_continue) = 1; + EXPR_WFL_LINECOL (break_continue) = location; + return break_continue; +} + +/* Verification of a break/continue statement. */ + +static tree +patch_bc_statement (node) + tree node; +{ + tree bc_label = EXIT_BLOCK_LABELED_BLOCK (node), target_stmt; + int is_unlabeled = 0; + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* Not having a target means that the break/continue statement is + unlabeled. We try to find a descent label for it */ + if (!bc_label) + { + is_unlabeled = 1; + /* There should be a loop to branch to */ + if (ctxp->current_loop) + { + /* At that stage, we're in the loop body, which is + encapsulated around a LABELED_BLOCK_EXPR. So searching + the current loop label requires us to consider the + labeled block before the current one. */ + if (!LOOP_HAS_LABEL_SKIP_P (ctxp->current_loop)) + fatal ("unlabeled loop has not installed label -- " + "patch_bc_statement"); + bc_label = TREE_CHAIN (ctxp->current_labeled_block); + } + /* Not having a loop to break/continue to is an error */ + else + { + parse_error_context (wfl_operator, "`%s' must be in loop%s", + (IS_BREAK_STMT_P (node) ? "break" : "continue"), + (IS_BREAK_STMT_P (node) ? " or switch" : "")); + return error_mark_node; + } + } + /* Having an identifier here means that the target is unknown. */ + else if (TREE_CODE (bc_label) == IDENTIFIER_NODE) + { + parse_error_context (wfl_operator, "No label definition found for `%s'", + IDENTIFIER_POINTER (bc_label)); + return error_mark_node; + } + + /* Find the statement we're targeting. */ + target_stmt = LABELED_BLOCK_BODY (bc_label); + + /* 14.13 The break Statement */ + if (IS_BREAK_STMT_P (node)) + { + /* Named break are always fine, as far as they have a target + (already verified). Anonymous break need to target + while/do/for/switch */ + if (is_unlabeled && + !(TREE_CODE (target_stmt) == LOOP_EXPR /* do/while/for */ + || 0)) /* switch FIXME */ + { + parse_error_context (wfl_operator, + "`break' must be in loop or switch"); + return error_mark_node; + } + /* If previously unlabeled, install the new found label */ + if (is_unlabeled) + EXIT_BLOCK_LABELED_BLOCK (node) = bc_label; + } + /* 14.14 The continue Statement */ + /* The continue statement must always target a loop */ + else + { + if (TREE_CODE (target_stmt) != LOOP_EXPR) /* do/while/for */ + { + parse_error_context (wfl_operator, "`continue' must be in loop"); + return error_mark_node; + } + /* Everything looks good. We can fix the `continue' jump to go + at the place in the loop were the continue is. The continue + is the current labeled block, by construction. */ + EXIT_BLOCK_LABELED_BLOCK (node) = ctxp->current_labeled_block; + } + + /* Our break/continue don't return values. */ + TREE_TYPE (node) = void_type_node; + /* Encapsulate the break within a compound statement so that it's + expanded all the times by expand_expr (and not clobered + sometimes, like after a if statement) */ + node = add_stmt_to_compound (NULL_TREE, void_type_node, node); + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* Process the exit expression belonging to a loop. Its type must be + boolean. */ + +static tree +patch_exit_expr (node) + tree node; +{ + tree expression = TREE_OPERAND (node, 0); + TREE_TYPE (node) = error_mark_node; + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* The type of expression must be boolean */ + if (TREE_TYPE (expression) != boolean_type_node) + { + parse_error_context + (wfl_operator, + "Incompatible type for loop conditional. Can't convert `%s' to " + "`boolean'", + lang_printable_name (TREE_TYPE (expression))); + return error_mark_node; + } + /* Now we know things are allright, invert the condition, fold and + return */ + TREE_OPERAND (node, 0) = + fold (build1 (TRUTH_NOT_EXPR, boolean_type_node, expression)); + TREE_TYPE (node) = void_type_node; + return node; +} diff --git a/gcc/java/parse.h b/gcc/java/parse.h new file mode 100644 index 00000000000..50d51401149 --- /dev/null +++ b/gcc/java/parse.h @@ -0,0 +1,599 @@ +/* Language parser definitions for the GNU compiler for the Java(TM) language. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +#ifndef JV_LANG_H +#define JV_LANG_H + +#include "lex.h" + +/* Extern global variable declarations */ +extern int java_error_count; +extern struct obstack temporary_obstack; +extern struct obstack permanent_obstack; +extern int quiet_flag; + +#ifndef JC1_LITE +/* Function extern to java/ */ +extern int int_fits_type_p PROTO ((tree, tree)); +extern tree stabilize_reference PROTO ((tree)); +#endif + +/* Macros for verbose debug info */ +#ifdef VERBOSE_SKELETON +#define RULE( rule ) printf ( "jv_yacc:%d: rule %s\n", lineno, rule ) +#else +#define RULE( rule ) +#endif + +#ifdef SOURCE_FRONTEND_DEBUG +#undef SOURCE_FRONTEND_DEBUG +#define SOURCE_FRONTEND_DEBUG(X) \ + {if (!quiet_flag) {printf ("* "); printf X; putchar ('\n');} } +#else +#define SOURCE_FRONTEND_DEBUG(X) +#endif + +/* Macro for error recovering */ +#ifdef YYDEBUG +#define RECOVERED \ + { if (!quiet_flag) {printf ("** Recovered\n");} } +#define DRECOVERED(s) \ + { if (!quiet_flag) {printf ("** Recovered (%s)\n", #s);}} +#else +#define RECOVERED +#define DRECOVERED(s) +#endif + +#define DRECOVER(s) {yyerrok; DRECOVERED(s)} +#define RECOVER {yyerrok; RECOVERED} + +#define YYERROR_NOW ctxp->java_error_flag = 1 +#define YYNOT_TWICE if (ctxp->prevent_ese != lineno) + +/* Accepted modifiers */ +#define CLASS_MODIFIERS ACC_PUBLIC|ACC_ABSTRACT|ACC_FINAL +#define FIELD_MODIFIERS ACC_PUBLIC|ACC_PROTECTED|ACC_PRIVATE|ACC_FINAL| \ + ACC_STATIC|ACC_TRANSIENT|ACC_VOLATILE +#define METHOD_MODIFIERS ACC_PUBLIC|ACC_PROTECTED|ACC_PRIVATE|ACC_ABSTRACT| \ + ACC_STATIC|ACC_FINAL|ACC_SYNCHRONIZED|ACC_NATIVE +#define INTERFACE_MODIFIERS ACC_PUBLIC|ACC_ABSTRACT +#define INTERFACE_METHOD_MODIFIERS ACC_PUBLIC|ACC_ABSTRACT +#define INTERFACE_FIELD_MODIFIERS ACC_PUBLIC|ACC_STATIC|ACC_FINAL + +/* Getting a modifier WFL */ +#define MODIFIER_WFL(M) (ctxp->modifier_ctx [(M) - PUBLIC_TK]) + +/* Check on modifiers */ +#define THIS_MODIFIER_ONLY(f, m, v, count, l) \ + if ((f) & (m)) \ + { \ + tree node = ctxp->modifier_ctx [v]; \ + if ((l) \ + && ((EXPR_WFL_COLNO (node) > EXPR_WFL_COLNO (l)) \ + || (EXPR_WFL_LINENO (node) > EXPR_WFL_LINENO (l)))) \ + l = node; \ + else if (!(l)) \ + l = node; \ + count++; \ + } + +#define ABSTRACT_CHECK(flag, v, cl, s) \ + if ((flag) & (v)) \ + parse_error_context (cl, s " method can't be abstract"); + +/* Misc. */ +#define exit_java_complete_class() \ + { \ + pop_obstacks (); \ + return; \ + } + +#define CLASS_OR_INTERFACE(decl, s1, s2) \ + (decl ? \ + ((get_access_flags_from_decl (TYPE_NAME (TREE_TYPE (decl))) \ + & ACC_INTERFACE) ? \ + s2 : s1) : ((s1 [0]=='S'|| s1 [0]=='s') ? \ + (s1 [0]=='S' ? "Supertype" : "supertype") : \ + (s1 [0] > 'A' ? "Type" : "type"))) + +/* Pedantic warning on obsolete modifiers. Note: when cl is NULL, + flags was set artificially, such as for a interface method */ +#define OBSOLETE_MODIFIER_WARNING(cl, flags, modifier, format, arg) \ + { \ + if ((cl) && ((flags) & (modifier))) \ + parse_warning_context (cl, \ + "Discouraged redundant use of `%s' modifier " \ + "in declaration of " format, \ + java_accstring_lookup (modifier), arg); \ + } + +/* Quickly build a temporary pointer on hypothetical type NAME. */ +#define BUILD_PTR_FROM_NAME(ptr, name) \ + { \ + ptr = build (POINTER_TYPE, NULL_TREE); \ + TYPE_NAME (ptr) = name; \ + } + +#define INCOMPLETE_TYPE_P(NODE) \ + ((TREE_CODE (NODE) == TREE_LIST) \ + && (TREE_CODE (TREE_PURPOSE (NODE)) == POINTER_TYPE) \ + && (TREE_TYPE (TREE_PURPOSE (NODE)) == NULL_TREE)) + +/* Set the EMIT_LINE_NOTE flag of a EXPR_WLF to 1 if debug information + are requested. Works in the context of a parser rule. */ +#define JAVA_MAYBE_GENERATE_DEBUG_INFO(node) \ + (debug_info_level != DINFO_LEVEL_NONE ? \ + EXPR_WFL_EMIT_LINE_NOTE (node) = 1, node : node) + +/* Types classification, according to the JLS, section 4.2 */ +#define JFLOAT_TYPE_P(TYPE) (TREE_CODE ((TYPE)) == REAL_TYPE) +#define JINTEGRAL_TYPE_P(TYPE) ((TREE_CODE ((TYPE)) == INTEGER_TYPE) \ + || (TREE_CODE ((TYPE)) == CHAR_TYPE)) +#define JNUMERIC_TYPE_P(TYPE) (JFLOAT_TYPE_P ((TYPE)) \ + || JINTEGRAL_TYPE_P ((TYPE))) +#define JPRIMITIVE_TYPE_P(TYPE) (JNUMERIC_TYPE_P ((TYPE)) \ + || (TREE_CODE ((TYPE)) == BOOLEAN_TYPE)) + +/* Not defined in the LRM */ +#define JSTRING_TYPE_P(TYPE) ((TYPE) == string_type_node || \ + (TREE_CODE (TYPE) == POINTER_TYPE && \ + TREE_TYPE (op1_type) == string_type_node)) + +#define JREFERENCE_TYPE_P(TYPE) (TREE_CODE (TYPE) == RECORD_TYPE || \ + (TREE_CODE (TYPE) == POINTER_TYPE && \ + TREE_CODE (TREE_TYPE (TYPE)) == RECORD_TYPE)) + +/* Other predicate */ +#define DECL_P(NODE) (NODE && (TREE_CODE (NODE) == PARM_DECL \ + || TREE_CODE (NODE) == VAR_DECL \ + || TREE_CODE (NODE) == FIELD_DECL)) + +#define TYPE_INTERFACE_P(TYPE) \ + (CLASS_P (TYPE) && CLASS_INTERFACE (TYPE_NAME (TYPE))) + +#define TYPE_CLASS_P(TYPE) (CLASS_P (TYPE) \ + && !CLASS_INTERFACE (TYPE_NAME (TYPE)) \ + && !TYPE_ARRAY_P (TYPE)) + +/* Standard error messages */ +#define ERROR_CANT_CONVERT_TO_BOOLEAN(OPERATOR, NODE, TYPE) \ + parse_error_context \ + ((OPERATOR), "Incompatible type for `%s'. Can't convert `%s' to " \ + "boolean", operator_string ((NODE)), lang_printable_name ((TYPE))) + +#define ERROR_CANT_CONVERT_TO_NUMERIC(OPERATOR, NODE, TYPE) \ + parse_error_context \ + ((OPERATOR), "Incompatible type for `%s'. Can't convert `%s' to " \ + "numeric type", operator_string ((NODE)), lang_printable_name ((TYPE))) + +#define ERROR_CAST_NEEDED_TO_INTEGRAL(OPERATOR, NODE, TYPE) \ + parse_error_context \ + ((OPERATOR), (JPRIMITIVE_TYPE_P (TYPE) ? \ + "Incompatible type for `%s'. Explicit cast needed to convert " \ + "`%s' to integral" : "Incompatible type for `%s'. Can't convert " \ + "`%s' to integral"), operator_string ((NODE)), \ + lang_printable_name ((TYPE))) + +#define ERROR_VARIABLE_NOT_INITIALIZED(WFL, V) \ + parse_error_context \ + ((WFL), "Variable `%s' may not have been initialized", \ + IDENTIFIER_POINTER (V)) + +/* Definition for loop handling. This Java's own definition of a loop + body. See parse.y for documentation. It's valid once you hold a + loop's body (LOOP_EXPR_BODY) */ + +/* The loop main block is the one hold the condition and the loop body */ +#define LOOP_EXPR_BODY_MAIN_BLOCK(NODE) TREE_OPERAND (NODE, 0) +/* And then there is the loop update block */ +#define LOOP_EXPR_BODY_UPDATE_BLOCK(NODE) TREE_OPERAND (NODE, 1) + +/* Inside the loop main block, there is the loop condition and the + loop body. They may be reversed if the loop being described is a + do-while loop. NOTE: if you use a WFL around the EXIT_EXPR so you + can issue debug info for it, the EXIT_EXPR will be one operand + further. */ +#define LOOP_EXPR_BODY_CONDITION_EXPR(NODE, R) \ + TREE_OPERAND (LOOP_EXPR_BODY_MAIN_BLOCK (NODE), (R ? 1 : 0)) + +/* Here is the labeled block the loop real body is encapsulated in */ +#define LOOP_EXPR_BODY_LABELED_BODY(NODE, R) \ + TREE_OPERAND (LOOP_EXPR_BODY_MAIN_BLOCK (NODE), (R ? 0 : 1)) +/* And here is the loop's real body */ +#define LOOP_EXPR_BODY_BODY_EXPR(NODE, R) \ + LABELED_BLOCK_BODY (LOOP_EXPR_BODY_LABELED_BODY(NODE, R)) + +/* Does a loop have a label ? */ +#define LOOP_HAS_LABEL_P(LOOP) \ + (ctxp->current_labeled_block \ + && LABELED_BLOCK_BODY (ctxp->current_labeled_block) == (LOOP)) + +/* Same operation than the one performed above, but considering the + previous labeled block */ +#define LOOP_HAS_LABEL_SKIP_P(LOOP) \ + (ctxp->current_labeled_block \ + && TREE_CHAIN (ctxp->current_labeled_block) \ + && LABELED_BLOCK_BODY (TREE_CHAIN (ctxp->current_labeled_block)) == (LOOP)) + +#define PUSH_LABELED_BLOCK(B) \ + { \ + TREE_CHAIN (B) = ctxp->current_labeled_block; \ + ctxp->current_labeled_block = (B); \ + } +#define POP_LABELED_BLOCK() \ + ctxp->current_labeled_block = TREE_CHAIN (ctxp->current_labeled_block) + +#define PUSH_LOOP(L) \ + { \ + TREE_CHAIN (L) = ctxp->current_loop; \ + ctxp->current_loop = (L); \ + } +#define POP_LOOP() ctxp->current_loop = TREE_CHAIN (ctxp->current_loop) + + +/* Invocation modes, as returned by invocation_mode (). */ +enum { + INVOKE_STATIC, + INVOKE_NONVIRTUAL, + INVOKE_SUPER, + INVOKE_INTERFACE, + INVOKE_VIRTUAL, +}; + +/* We need the resolution stuff only if we compile jc1 */ +#ifndef JC1_LITE + +/* Unresolved type identifiers handling. When we process the source + code, we blindly accept an unknown type identifier and try to + resolve it later. When an unknown type identifier is encountered + and used, we record in a struct jdep element what the incomplete + type is and what it should patch. Later, java_complete_class will + process all classes known to have unresolved type + dependencies. Within each of these classes, this routine will + process unresolved type dependencies (JDEP_TO_RESOLVE), patch what + needs to be patched in the dependent tree node (JDEP_GET_PATCH, + JDEP_APPLY_PATCH) and perform other actions dictated by the context + of the patch (JDEP_KIND). The ideas are: we patch only what needs + to be patched, and with java_complete_class called at the right + time, we will start processing incomplete function bodies tree + nodes with everything external to function's bodies already + completed, it makes things much simpler. */ + +enum jdep_code { + JDEP_NO_PATCH, /* Must be first */ + JDEP_SUPER, /* Patch the type of one type + supertype. Requires some check + before it's done */ + JDEP_FIELD, /* Patch the type of a class field */ + + /* JDEP_{METHOD,METHOD_RETURN,METHOD_END} to be kept in order */ + JDEP_METHOD, /* Mark the beginning of the patching + of a method declaration, including + it's arguments */ + JDEP_METHOD_RETURN, /* Mark the beginning of the patching + of a method declaration. Arguments + aren't patched, only the returned + type is */ + JDEP_METHOD_END, /* Mark the end of the patching of a + method declaration. It indicates + that it's time to compute and + install a new signature */ + + JDEP_INTERFACE, /* Patch the type of a Class/interface + extension */ + JDEP_VARIABLE, /* Patch the type of a variable declaration */ + JDEP_PARM, /* Patch the type of a parm declaration */ + JDEP_TYPE, /* Patch a random tree node type, + without the need for any specific + actions */ +}; + +typedef struct _jdep { +#ifdef ONLY_INT_FIELDS + int kind : 8; /* Type of patch */ +#else + enum jdep_code kind : 8; +#endif + + int flag0 : 1; /* Some flags */ + tree decl; /* Tied decl/or WFL */ + tree solv; /* What to solve */ + tree wfl; /* Where thing to resolve where found */ + tree misc; /* Miscellaneous info (optional). */ + tree *patch; /* Address of a location to patch */ + struct _jdep *next; /* Linked list */ +} jdep; + + +#define JDEP_DECL(J) ((J)->decl) +#define JDEP_DECL_WFL(J) ((J)->decl) +#define JDEP_KIND(J) ((J)->kind) +#define JDEP_SOLV(J) ((J)->solv) +#define JDEP_WFL(J) ((J)->wfl) +#define JDEP_MISC(J) ((J)->misc) +#define JDEP_CLASS(J) ((J)->class) +#define JDEP_APPLY_PATCH(J,P) (*(J)->patch = (P)) +#define JDEP_GET_PATCH(J) ((J)->patch) +#define JDEP_CHAIN(J) ((J)->next) +#define JDEP_TO_RESOLVE(J) (TREE_PURPOSE ((J)->solv)) +#define JDEP_RESOLVED_DECL(J) ((J)->solv ? TREE_PURPOSE ((J)->solv):NULL_TREE) +#define JDEP_RESOLVED(J, D) \ + { \ + TREE_PURPOSE ((J)->solv) = D; \ + TREE_VALUE ((J)->solv) = (J)->solv; \ + } +#define JDEP_RESOLVED_P(J) (!(J)->solv || \ + TREE_VALUE ((J)->solv) == (J)->solv) + +typedef struct _jdeplist { + jdep *first; + jdep *last; + struct _jdeplist *next; +} jdeplist; +static jdeplist *reverse_jdep_list (); + +#endif /* JC1_LITE */ + +#define CLASSD_FIRST(CD) ((CD)->first) +#define CLASSD_LAST(CD) ((CD)->last) +#define CLASSD_CHAIN(CD) ((CD)->next) + +#define JDEP_INSERT(L,J) \ + { \ + if (!(L)->first) \ + (L)->last = (L)->first = (J); \ + else \ + { \ + JDEP_CHAIN ((L)->last) = (J); \ + (L)->last = (J); \ + } \ + } + +/* Insert a DECL in the current block */ +#define BLOCK_CHAIN_DECL(NODE) \ + { \ + TREE_CHAIN ((NODE)) = \ + BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)); \ + BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)) = (NODE); \ + } + +#define BLOCK_EXPR_DECLS(NODE) BLOCK_VARS(NODE) +#define BLOCK_EXPR_BODY(NODE) BLOCK_SUBBLOCKS(NODE) +#define BLOCK_EXPR_ORIGIN(NODE) BLOCK_ABSTRACT_ORIGIN(NODE) + +/* Merge an other line to the source line number of a decl. Used to + remember function's end. */ +#define DECL_SOURCE_LINE_MERGE(DECL,NO) DECL_SOURCE_LINE(DECL) |= (NO << 16) + +/* Retrieve those two info separately. */ +#define DECL_SOURCE_LINE_FIRST(DECL) (DECL_SOURCE_LINE(DECL) & 0x0000ffff) +#define DECL_SOURCE_LINE_LAST(DECL) (DECL_SOURCE_LINE(DECL) >> 16) + +/* Build a WFL for expression nodes */ +#define BUILD_EXPR_WFL(NODE, WFL) \ + build_expr_wfl ((NODE), input_filename, EXPR_WFL_LINENO ((WFL)), \ + EXPR_WFL_COLNO ((WFL))) + +#define EXPR_WFL_QUALIFICATION(WFL) TREE_OPERAND ((WFL), 1) +#define QUAL_WFL(NODE) TREE_PURPOSE (NODE) +#define QUAL_RESOLUTION(NODE) TREE_VALUE (NODE) +#define QUAL_DECL_TYPE(NODE) \ + (TREE_CODE (TREE_TYPE (NODE)) == POINTER_TYPE ? \ + TREE_TYPE (TREE_TYPE (NODE)) : TREE_TYPE (NODE)) + +/* Handy macros for the walk operation */ +#define COMPLETE_CHECK_OP(NODE, N) \ +{ \ + TREE_OPERAND ((NODE), (N)) = \ + java_complete_tree (TREE_OPERAND ((NODE), (N))); \ + if (TREE_OPERAND ((NODE), (N)) == error_mark_node) \ + return error_mark_node; \ +} +#define COMPLETE_CHECK_OP_0(NODE) COMPLETE_CHECK_OP(NODE, 0) +#define COMPLETE_CHECK_OP_1(NODE) COMPLETE_CHECK_OP(NODE, 1) + +/* Parser context data structure. */ +struct parser_ctxt { + + char *filename; /* Current filename */ + FILE *finput; /* Current file input stream */ + struct parser_ctxt *next; + + struct java_line *p_line, *c_line; /* Previous and current line */ + java_lc elc; /* Error's line column info */ + unicode_t unget_utf8_value; /* An unget utf8 value */ + int ccb_indent; /* Keep track of {} indent, lexer */ + int first_ccb_indent1; /* First { at ident level 1 */ + int last_ccb_indent1; /* Last } at ident level 1 */ + int parser_ccb_indent; /* Keep track of {} indent, parser */ + int osb_number; /* Keep track of ['s */ + int minus_seen; /* Integral literal overflow */ + int lineno; /* Current lineno */ + int java_error_flag; /* Report error when true */ + + /* This section is defined only if we compile jc1 */ +#ifndef JC1_LITE + tree modifier_ctx [11]; /* WFL of modifiers */ + tree current_class; /* Current class */ + tree current_function_decl; /* Current function decl, save/restore */ + + JCF *current_jcf; /* CU jcf */ + + int prevent_ese; /* Prevent expression statement error */ + int class_err; /* Flag to report certain errors */ + + int formal_parameter_number; /* Number of parameters found */ + int interface_number; /* # itfs declared to extend an itf def */ + + tree package; /* Defined package ID */ + + tree incomplete_class; /* List of non-complete classes */ + tree current_parsed_class; /* Class currently parsed */ + tree class_list; /* List of classes in a CU */ + jdeplist *classd_list; /* Classe dependencies in a CU */ + + tree non_static_initialized; /* List of non static initialized fields */ + tree static_initialized; /* List of static non final initialized */ + + tree import_list; /* List of import */ + tree import_demand_list; /* List of import on demand */ + + tree current_loop; /* List of the currently nested loops */ + tree current_labeled_block; /* List of currently nested + labeled blocks. */ + + int pending_block; /* Pending block to close */ +#endif /* JC1_LITE */ +}; + +/* Functions declarations */ +#ifndef JC1_LITE +static char *java_accstring_lookup PROTO ((int)); +static void parse_error PROTO ((char *)); +static void redefinition_error PROTO ((char *,tree, tree, tree)); +static void check_modifiers PROTO ((char *, int, int)); +static tree create_class PROTO ((int, tree, tree, tree)); +static tree create_interface PROTO ((int, tree, tree)); +static tree find_field PROTO ((tree, tree)); +static tree lookup_field_wrapper PROTO ((tree, tree)); +static int duplicate_declaration_error PROTO ((tree, tree, tree, tree)); +static void register_fields PROTO ((int, tree, tree)); +static tree parser_qualified_classname PROTO ((tree)); +static int parser_check_super PROTO ((tree, tree, tree)); +static int parser_check_super_interface PROTO ((tree, tree, tree)); +static void check_modifiers_consistency PROTO ((int)); +static tree lookup_cl PROTO ((tree)); +static tree lookup_java_method2 PROTO ((tree, tree, int)); +static tree method_header PROTO ((int, tree, tree, tree)); +static tree method_declarator PROTO ((tree, tree)); +static void parse_error_context VPROTO ((tree cl, char *msg, ...)); +static void parse_warning_context VPROTO ((tree cl, char *msg, ...)); +static void complete_class_report_errors PROTO ((jdep *)); +static int process_imports PROTO ((void)); +static void read_import_dir PROTO ((tree)); +static int find_in_imports_on_demand PROTO ((tree)); +static int find_in_imports PROTO ((tree)); +static int check_pkg_class_access PROTO ((tree, tree)); +static tree resolve_class PROTO ((tree, tree, tree)); +static tree do_resolve_class PROTO ((tree, tree, tree)); +static void declare_local_variables PROTO ((int, tree, tree)); +static void source_start_java_method PROTO ((tree)); +static void source_end_java_method PROTO ((void)); +static void expand_start_java_method PROTO ((tree)); +static tree find_name_in_single_imports PROTO ((tree)); +static void check_abstract_method_header PROTO ((tree)); +static tree lookup_java_interface_method2 PROTO ((tree, tree)); +static tree resolve_expression_name PROTO ((tree)); +static tree maybe_create_class_interface_decl PROTO ((tree, tree, tree)); +static int check_class_interface_creation PROTO ((int, int, tree, tree, tree, tree)); +static tree patch_method_invocation_stmt PROTO ((tree, tree, tree, int *)); +static int breakdown_qualified PROTO ((tree *, tree *, tree)); +static tree resolve_and_layout PROTO ((tree, tree)); +static tree resolve_no_layout PROTO ((tree, tree)); +static int identical_subpath_p PROTO ((tree, tree)); +static int invocation_mode PROTO ((tree, int)); +static tree refine_accessible_methods_list PROTO ((int, tree)); +static tree patch_invoke PROTO ((tree, tree, tree, tree)); +static tree lookup_method_invoke PROTO ((int, tree, tree, tree, tree)); +static tree register_incomplete_type PROTO ((int, tree, tree, tree)); +static tree obtain_incomplete_type PROTO ((tree)); +static tree java_complete_tree PROTO ((tree)); +static void java_complete_expand_method PROTO ((tree)); +static int unresolved_type_p PROTO ((tree, tree *)); +static void create_jdep_list PROTO ((struct parser_ctxt *)); +static tree build_expr_block PROTO ((tree, tree)); +static tree enter_block PROTO ((void)); +static tree exit_block PROTO ((void)); +static tree lookup_name_in_blocks PROTO ((tree)); +static void maybe_absorb_scoping_blocks PROTO ((void)); +static tree build_method_invocation PROTO ((tree, tree)); +static tree build_assignment PROTO ((int, int, tree, tree)); +static tree build_binop PROTO ((enum tree_code, int, tree, tree)); +static tree patch_assignment PROTO ((tree, tree, tree )); +static tree patch_binop PROTO ((tree, tree, tree)); +static tree build_unaryop PROTO ((int, int, tree)); +static tree build_incdec PROTO ((int, int, tree, int)); +static tree patch_unaryop PROTO ((tree, tree)); +static tree build_cast PROTO ((int, tree, tree)); +static tree patch_cast PROTO ((tree, tree, tree)); +static int valid_ref_assignconv_cast_p PROTO ((tree, tree, int)); +static int can_cast_to_p PROTO ((tree, tree)); +static tree build_unresolved_array_type PROTO ((tree)); +static tree build_array_ref PROTO ((int, tree, tree)); +static tree patch_array_ref PROTO ((tree, tree, tree)); +static tree make_qualified_name PROTO ((tree, tree, int)); +static tree merge_qualified_name PROTO ((tree, tree)); +static tree make_qualified_primary PROTO ((tree, tree, int)); +static int resolve_qualified_expression_name PROTO ((tree, tree *, tree *, tree *)); +static void qualify_ambiguous_name PROTO ((tree)); +static void maybe_generate_clinit PROTO ((void)); +static tree resolve_field_access PROTO ((tree, tree *, tree *)); +static tree build_newarray_node PROTO ((tree, tree, int)); +static tree patch_newarray PROTO ((tree)); +static tree resolve_type_during_patch PROTO ((tree)); +static int not_initialized_as_it_should_p PROTO ((tree)); +static tree build_this PROTO ((int)); +static tree build_return PROTO ((int, tree)); +static tree patch_return PROTO ((tree)); +static tree maybe_access_field PROTO ((tree, tree, tree)); +static int complete_function_arguments PROTO ((tree)); +static int check_for_static_method_reference PROTO ((tree, tree, tree, tree, tree)); +static int not_accessible_p PROTO ((tree, tree, int)); +static int class_in_current_package PROTO ((tree)); +static tree build_if_else_statement PROTO ((int, tree, tree, tree)); +static tree patch_if_else_statement PROTO ((tree)); +static tree add_stmt_to_compound PROTO ((tree, tree, tree)); +static tree patch_exit_expr PROTO ((tree)); +static tree build_labeled_block PROTO ((int, tree, tree)); +static tree generate_labeled_block PROTO (()); +static tree complete_labeled_statement PROTO ((tree, tree)); +static tree build_bc_statement PROTO ((int, int, tree)); +static tree patch_bc_statement PROTO ((tree)); +static tree patch_loop_statement PROTO ((tree)); +static tree build_new_loop PROTO ((tree)); +static tree build_loop_body PROTO ((int, tree, int)); +static tree complete_loop_body PROTO ((int, tree, tree, int)); +static tree build_debugable_stmt PROTO ((int, tree)); +static tree complete_for_loop PROTO ((int, tree, tree, tree)); + +void safe_layout_class PROTO ((tree)); +void java_complete_class PROTO ((void)); +void java_check_circular_reference PROTO ((void)); +void java_check_final PROTO ((void)); +void java_check_methods PROTO ((void)); +void java_layout_classes PROTO ((void)); +tree java_method_add_stmt PROTO ((tree, tree)); +char *java_get_line_col PROTO ((char *, int, int)); +#endif /* JC1_LITE */ + +/* Always in use, no matter what you compile */ + +void java_push_parser_context PROTO ((void)); +void java_init_lex PROTO ((void)); +int yyparse PROTO ((void)); +int yylex (); +void yyerror PROTO ((char *)); + +#endif diff --git a/gcc/java/parse.y b/gcc/java/parse.y new file mode 100644 index 00000000000..50a467962fc --- /dev/null +++ b/gcc/java/parse.y @@ -0,0 +1,8035 @@ +/* Source code parsing and tree node generation for the GNU compiler + for the Java(TM) language. + Copyright (C) 1997, 1998 Free Software Foundation, Inc. + Contributed by Alexandre Petit-Bianco (apbianco@cygnus.com) + +This file is part of GNU CC. + +GNU CC 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, +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 +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' +constructor_declaration: added two rules to accept 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 +#include +#include +#include +#ifdef __STDC__ +#include +#else +#include +#endif + +#include "config.h" +#include "tree.h" +#include "rtl.h" +#include "obstack.h" +#include "flags.h" +#include "java-tree.h" +#include "jcf.h" +#include "lex.h" +#include "parse.h" +#include "zipfile.h" + +/* Number of error found so far. */ +int java_error_count; +/* Number of warning found so far. */ +int java_warning_count; + +/* The current parser context */ +static struct parser_ctxt *ctxp; + +/* 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 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)% \ + (sizeof (binop_lookup) / sizeof (binop_lookup[0]))] + +/* Fake WFL used to report error message. It is initialized once if + needed and reused with it's location information is overriden. */ +static tree wfl_operator = NULL_TREE; + +/* The "$L" identifier we use to create labels. */ +static tree label_id; +%} + +%union { + tree node; + int sub_token; + struct { + int token; + int location; + } operator; + int value; +} + +%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 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 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 modifiers MODIFIER_TK + +%type super ID_TK identifier +%type name simple_name qualified_name +%type class_declaration type_declaration compilation_unit + field_declaration method_declaration extends_interfaces + interfaces interface_type_list + interface_declaration class_member_declaration + import_declarations package_declaration + type_declarations interface_body + interface_member_declaration constant_declaration + interface_member_declarations interface_type + abstract_method_declaration interface_type_list +%type class_body_declaration class_member_declaration + static_initializer constructor_declaration block +%type class_body_declarations +%type class_or_interface_type class_type class_type_list + constructor_declarator explicit_constructor_invocation +%type dim_expr dim_exprs this_or_super + +%type variable_declarator_id variable_declarator + variable_declarators variable_initializer + variable_initializers + +%type class_body +%type block_statement local_variable_declaration_statement + block_statements local_variable_declaration +%type 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_creation_expression array_type + 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 + unary_expression_not_plus_minus 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 +%type return_statement break_statement continue_statement + +%type ASSIGN_TK MULT_ASSIGN_TK DIV_ASSIGN_TK +%type REM_ASSIGN_TK PLUS_ASSIGN_TK MINUS_ASSIGN_TK +%type LS_ASSIGN_TK SRS_ASSIGN_TK ZRS_ASSIGN_TK +%type AND_ASSIGN_TK XOR_ASSIGN_TK OR_ASSIGN_TK +%type ASSIGN_ANY_TK assignment_operator +%token EQ_TK GTE_TK ZRS_TK SRS_TK GT_TK LTE_TK LS_TK +%token BOOL_AND_TK AND_TK BOOL_OR_TK OR_TK INCR_TK PLUS_TK +%token DECR_TK MINUS_TK MULT_TK DIV_TK XOR_TK REM_TK NEQ_TK +%token NEG_TK REL_QM_TK REL_CL_TK NOT_TK LT_TK +%token OP_TK OSB_TK DOT_TK +%type THIS_TK SUPER_TK RETURN_TK BREAK_TK CONTINUE_TK + +%type method_body + +%type literal INT_LIT_TK FP_LIT_TK BOOL_LIT_TK CHAR_LIT_TK + STRING_LIT_TK NULL_TK VOID_TK + +%type IF_TK WHILE_TK FOR_TK + +%type formal_parameter_list formal_parameter + method_declarator method_header + +%type primitive_type reference_type type + BOOLEAN_TK INTEGRAL_TK FP_TK + +%% +/* 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 OSB_TK CSB_TK + { + $$ = build_java_array_type ($1, -1); + CLASS_LOADED_P ($$) = 1; + } +| name OSB_TK CSB_TK + { $$ = build_unresolved_array_type ($1); } +| array_type OSB_TK CSB_TK + { $$ = build_unresolved_array_type ($1); } +| primitive_type OSB_TK error + {RULE ("']' expected"); RECOVER;} +| array_type OSB_TK error + {RULE ("']' expected"); RECOVER;} +; + +/* 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); } +| 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), node, last_name; + int i = IDENTIFIER_LENGTH (name)-1; + 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: `%s' and `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (err)); + } + else + { + IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (last_name) = 1; + node = build_tree_list ($2, last_name); + TREE_CHAIN (node) = ctxp->import_list; + ctxp->import_list = node; + } + } +| 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 node = build_tree_list ($2, NULL_TREE); + if (!IS_AN_IMPORT_ON_DEMAND_P (name)) + { + read_import_dir ($2); + IS_AN_IMPORT_ON_DEMAND_P (name) = 1; + } + TREE_CHAIN (node) = ctxp->import_demand_list; + ctxp->import_demand_list = node; + } +| IMPORT_TK name DOT_TK error + {yyerror ("'*' expected"); RECOVER;} +| IMPORT_TK name DOT_TK MULT_TK error + {yyerror ("';' expected"); RECOVER;} +; + +type_declaration: + class_declaration + { + maybe_generate_clinit (); + $$ = $1; + } +| interface_declaration +| SC_TK + { $$ = NULL; } +| 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 `%s' 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 + { + $$ = $7; + } +| CLASS_TK identifier super interfaces + { create_class (0, $2, $3, $4); } + class_body + { + $$ = $6; + } +| 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 + { $$ = ctxp->current_parsed_class; } +| OCB_TK class_body_declarations CCB_TK + { $$ = ctxp->current_parsed_class; } +; + +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 */ +; + +class_member_declaration: + field_declaration +| method_declaration +| class_declaration /* Added, JDK1.1 inner classes */ +| interface_declaration /* Added, JDK1.1 inner classes */ +; + +/* 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 + { + int acc_count = 0; + + check_modifiers + ("Illegal modifier `%s' 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 + { + $$ = NULL; /* FIXME */ + } +| 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 + { $$ = NULL; } +; + +/* 19.8.3 Productions from 8.4: Method Declarations */ +method_declaration: + method_header + { + current_function_decl = $1; + source_start_java_method (current_function_decl); + } + method_body + { + BLOCK_EXPR_BODY + (DECL_FUNCTION_BODY (current_function_decl)) = $3; + maybe_absorb_scoping_blocks (); + exit_block (); /* Exit function's body. */ + + /* Merge last line of the function with first line, + directly in the function decl. It will be used to + emit correct debug info. */ + DECL_SOURCE_LINE_MERGE (current_function_decl, + ctxp->last_ccb_indent1); + } +| method_header error + {YYNOT_TWICE yyerror ("'{' expected"); RECOVER;} +; + +method_header: + type method_declarator throws + { $$ = method_header (0, $1, $2, NULL); } +| VOID_TK method_declarator throws + { $$ = method_header (0, void_type_node, $2, NULL); } +| modifiers type method_declarator throws + { $$ = method_header ($1, $2, $3, NULL); } +| modifiers VOID_TK method_declarator throws + { $$ = method_header ($1, void_type_node, $3, NULL); } +| type error + {RECOVER;} +| modifiers type error + {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 + { $$ = method_declarator ($1, NULL_TREE); } +| identifier OP_TK formal_parameter_list CP_TK + { $$ = method_declarator ($1, $3); } +| method_declarator OSB_TK CSB_TK + { + /* Issue a warning here: obsolete declaration. FIXME */ + $$ = NULL; /* FIXME */ + } +| 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); + } +| modifiers type variable_declarator_id /* Added, JDK1.1 final locals */ + { + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1)); + $$ = NULL; /* FIXME */ + } +| type error + {yyerror ("Missing identifier"); RECOVER;} +| modifiers type error + { + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1)); + yyerror ("Missing identifier"); RECOVER; + } +; + +throws: +| THROWS_TK class_type_list +| THROWS_TK error + {yyerror ("Missing class type term"); RECOVER;} +; + +class_type_list: + class_type +| class_type_list C_TK class_type +| class_type_list C_TK error + {yyerror ("Missing class type term"); RECOVER;} +; + +method_body: + block +| block SC_TK +| SC_TK + { $$ = NULL_TREE; } /* Probably not the right thing to do. */ +; + +/* 19.8.4 Productions from 8.5: Static Initializers */ +static_initializer: + static block + { + RULE ("STATIC_INITIALIZER"); + } +| static block SC_TK /* Shouldn't be here. FIXME */ + { + RULE ("STATIC_INITIALIZER"); + } +; + +static: /* Test lval.sub_token here */ + MODIFIER_TK + { + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1)); + } +; + +/* 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 + method without having specified the return type. FIXME */ +constructor_declaration: + constructor_declarator throws constructor_body + { + RULE ("CONSTRUCTOR_DECLARATION"); + } +| modifiers constructor_declarator throws constructor_body + { + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1)); + RULE ("CONSTRUCTOR_DECLARATION (modifier)"); + } +/* extra SC_TK, FIXME */ +| constructor_declarator throws constructor_body SC_TK + { + RULE ("CONSTRUCTOR_DECLARATION"); + } +/* extra SC_TK, FIXME */ +| modifiers constructor_declarator throws constructor_body SC_TK + { + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1)); + RULE ("CONSTRUCTOR_DECLARATION (modifier)"); + } +/* I'm not happy with the SC_TK addition. It isn't in the grammer and should + probably be matched by and empty statement. But it doesn't work. FIXME */ +; + +constructor_declarator: + simple_name OP_TK CP_TK +| simple_name OP_TK formal_parameter_list CP_TK +; + +constructor_body: + OCB_TK CCB_TK +| OCB_TK explicit_constructor_invocation CCB_TK +| OCB_TK block_statements CCB_TK +| OCB_TK explicit_constructor_invocation block_statements CCB_TK +; + +/* Error recovery for that rule moved down expression_statement: rule. */ +explicit_constructor_invocation: + this_or_super OP_TK CP_TK SC_TK +| this_or_super OP_TK argument_list CP_TK SC_TK + /* 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 +| name DOT_TK SUPER_TK OP_TK CP_TK SC_TK + {RULE ("explicit_constructor_invocation (X.super)");} +; + +this_or_super: /* Added, simplifies error diagnostics */ + THIS_TK + { + tree wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = $1.location; + $$ = wfl; + } +| SUPER_TK + { + tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = $1.location; + $$ = 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 + { + $$ = $4; + } +| modifiers INTERFACE_TK identifier + { create_interface ($1, $3, NULL_TREE); } + interface_body + { + $$ = $5; + } +| INTERFACE_TK identifier extends_interfaces + { create_interface (0, $2, $3); } + interface_body + { + $$ = $5; + } +| modifiers INTERFACE_TK identifier extends_interfaces + { create_interface ($1, $3, $4); } + interface_body + { + $$ = $6; + } +| INTERFACE_TK identifier error + {yyerror ("(here)'{' expected"); RECOVER;} +| modifiers INTERFACE_TK identifier error + {yyerror ("(there)'{' 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 */ +| interface_declaration /* Added, JDK1.1 inner classes */ +; + +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 + { + RULE ("ARRAY_INITIALIZER (empty)"); + } +| OCB_TK variable_initializers CCB_TK + { + RULE ("ARRAY_INITIALIZER (variable)"); + } +| OCB_TK C_TK CCB_TK + { + RULE ("ARRAY_INITIALIZER (,)"); + } +| OCB_TK variable_initializers C_TK CCB_TK + { + RULE ("ARRAY_INITIALIZER (variable, ,)"); + } +; + +variable_initializers: + variable_initializer +| variable_initializers C_TK variable_initializer +| variable_initializers C_TK error + {yyerror ("Missing term"); RECOVER;} +; + +/* 19.11 Production from 14: Blocks and Statements */ +block: + OCB_TK CCB_TK + { $$ = size_zero_node; } +| OCB_TK + { enter_block (); } + block_statements + CCB_TK + { + maybe_absorb_scoping_blocks (); + $$ = exit_block (); + } +; + +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 inner classes */ +; + +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); } +| modifiers type variable_declarators /* Added, JDK1.1 final locals */ + { declare_local_variables ($1, $2, $3); } +; + +statement: + statement_without_trailing_substatement +| labeled_statement + { RULE ("STATEMENT (labeled)"); } +| if_then_statement + { RULE ("STATEMENT (if-then)"); } +| if_then_else_statement + { RULE ("STATEMENT (if-then-else)"); } +| while_statement + { RULE ("STATEMENT (while)"); } +| for_statement + { + /* If the for loop is unlabeled, we must return the + block it was defined it. It our last chance to + get a hold on it. */ + if (!LOOP_HAS_LABEL_P ($$)) + $$ = exit_block (); + } +; + +statement_nsi: + statement_without_trailing_substatement +| labeled_statement_nsi + { RULE ("NSI STATEMENT (labeled)"); } +| if_then_else_statement_nsi + { RULE ("NSI STATEMENT (if-then-else)"); } +| while_statement_nsi + { RULE ("NSI STATEMENT (while)"); } +| for_statement_nsi + { RULE ("NSI STATEMENT (for)"); } +; + +statement_without_trailing_substatement: + block + { RULE ("STATEMENT (block)"); } +| empty_statement + { RULE ("STATEMENT (empty)"); } +| expression_statement + { RULE ("STATEMENT (expression)"); } +| switch_statement + { RULE ("STATEMENT (switch)"); } +| do_statement + { RULE ("STATEMENT (do)"); } +| break_statement + { RULE ("STATEMENT (break)"); } +| continue_statement + { RULE ("STATEMENT (continue)"); } +| return_statement +| synchronized_statement + { RULE ("STATEMENT (synchronized)"); } +| throw_statement + { RULE ("STATEMENT (throw)"); } +| try_statement + { RULE ("STATEMENT (try)"); } +; + +empty_statement: + SC_TK + { $$ = size_zero_node; } +; + +label_decl: + identifier REL_CL_TK + { + $$ = build_labeled_block (EXPR_WFL_LINECOL ($1), + EXPR_WFL_NODE ($1), $1); + pushlevel (2); + push_labeled_block ($$); + PUSH_LABELED_BLOCK ($$); + } +; + +labeled_statement: + label_decl statement + { + $$ = complete_labeled_statement ($1, $2); + pop_labeled_block (); + POP_LABELED_BLOCK (); + } +| identifier error + {yyerror ("':' expected"); RECOVER;} +; + +labeled_statement_nsi: + label_decl statement_nsi + { + $$ = complete_labeled_statement ($1, $2); + pop_labeled_block (); + POP_LABELED_BLOCK (); + } +; + +/* 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 */ + $$ = build_expr_wfl ($1, input_filename, lineno, 0); + /* We know we have a statement, so set the debug + info to be eventually generate here. */ + $$ = JAVA_MAYBE_GENERATE_DEBUG_INFO ($$); + } +| error SC_TK + { + if (ctxp->prevent_ese != lineno) + yyerror ("Invalid expression statement"); + DRECOVER (expr_stmt); + } +| error OCB_TK + { + if (ctxp->prevent_ese != lineno) + yyerror ("Invalid expression statement"); + DRECOVER (expr_stmt); + } +| error CCB_TK + { + if (ctxp->prevent_ese != lineno) + yyerror ("Invalid expression statement"); + DRECOVER (expr_stmt); + } +| this_or_super OP_TK error + {yyerror ("')' expected"); RECOVER;} +| this_or_super OP_TK CP_TK error + {yyerror ("';' expected"); RECOVER;} +| this_or_super OP_TK argument_list error + {yyerror ("')' expected"); RECOVER;} +| this_or_super OP_TK argument_list CP_TK error + {yyerror ("';' expected"); 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 + { + RULE ("++INCREMENT"); + } +| pre_decrement_expression + { + RULE ("--DECREMENT"); + } +| post_increment_expression + { + RULE ("INCREMENT++"); + } +| post_decrement_expression + { + RULE ("DECREMENT--"); + } +| method_invocation +| class_instance_creation_expression + { + RULE ("INSTANCE CREATION"); + } +; + +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_TK OP_TK expression CP_TK switch_block +| 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;} +; + +switch_block: + OCB_TK CCB_TK +| OCB_TK switch_labels CCB_TK +| OCB_TK switch_block_statement_groups CCB_TK +| OCB_TK switch_block_statement_groups switch_labels CCB_TK +; + +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 +| DEFAULT_TK REL_CL_TK +| 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 + { $$ = complete_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 + { $$ = complete_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 + { $$ = complete_loop_body ($4.location, $5, $2, 1); } +; + +for_statement: + for_begin SC_TK expression SC_TK for_update CP_TK statement + { $$ = complete_for_loop (EXPR_WFL_LINECOL ($3), $3, $5, $7);} +| for_begin SC_TK SC_TK for_update CP_TK statement + { + $$ = complete_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) = + size_zero_node; + } +| 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 + { $$ = complete_for_loop (EXPR_WFL_LINECOL ($3), $3, $5, $7);} +| for_begin SC_TK SC_TK for_update CP_TK statement_nsi + { + $$ = complete_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) = + size_zero_node; + } +; + +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); + IS_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 */ + { $$ = size_zero_node; } +| 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 */ + {$$ = size_zero_node;} +| 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 +| THROW_TK error + {yyerror ("Missing term"); RECOVER;} +| THROW_TK expression error + {yyerror ("';' expected"); RECOVER;} +; + +synchronized_statement: + synchronized OP_TK expression CP_TK block +| 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: /* Test lval.sub_token here */ + MODIFIER_TK + { + SOURCE_FRONTEND_DEBUG (("Modifiers: %d", $1)); + } +; + +try_statement: + TRY_TK block catches +| TRY_TK block finally +| TRY_TK block catches finally +| TRY_TK error + {yyerror ("'{' expected"); DRECOVER (try_statement);} +; + +catches: + catch_clause +| catches catch_clause +; + +catch_clause: + CATCH_TK OP_TK formal_parameter CP_TK block +| CATCH_TK error + {yyerror ("'(' expected"); RECOVER;} +| CATCH_TK OP_TK error CP_TK /* That's for () */ + {yyerror ("Missing term"); DRECOVER (1);} +| CATCH_TK OP_TK error + {yyerror ("Missing term"); DRECOVER (2);} +; + +finally: + FINALLY_TK block +| FINALLY_TK error + {yyerror ("'{' expected"); RECOVER; } +; + +/* 19.12 Production from 15: Expressions */ +primary: + primary_no_new_array +| array_creation_expression +; + +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 DOT_TK CLASS_TK doens't work. So we split the rule + 'type' into its components. Missing is something for array, + which will complete the reference_type part. FIXME */ +| name DOT_TK CLASS_TK /* Added, JDK1.1 class literals */ +| primitive_type DOT_TK CLASS_TK /* Added, JDK1.1 class literals */ +| VOID_TK DOT_TK CLASS_TK /* Added, JDK1.1 class literals */ + /* Added, JDK1.1 inner classes. Documentation is wrong + refering to a 'ClassName' (class_name) rule that doesn't + exist. Used name instead. */ +| name DOT_TK THIS_TK +| 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;} +; + +class_instance_creation_expression: + NEW_TK class_type OP_TK argument_list CP_TK + { + $$ = build_method_invocation ($2, $4); + TREE_SET_CODE ($$, JAVA_NEW_CLASS_EXPR); + } +| NEW_TK class_type OP_TK CP_TK + { + $$ = build_method_invocation ($2, NULL_TREE); + TREE_SET_CODE ($$, JAVA_NEW_CLASS_EXPR); + } + /* Added, JDK1.1 inner classes but modified to use + 'class_type' instead of 'TypeName' (type_name) mentionned + in the documentation but doesn't exist. */ +| NEW_TK class_type OP_TK argument_list CP_TK class_body +{$$ = $2;} +| NEW_TK class_type OP_TK CP_TK class_body +{$$ = $2;} + /* 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 +| something_dot_new identifier OP_TK CP_TK class_body +| something_dot_new identifier OP_TK argument_list CP_TK +| something_dot_new identifier OP_TK argument_list CP_TK class_body +| NEW_TK error SC_TK + {yyerror ("'(' expected"); DRECOVER(new_1);} +| NEW_TK class_type error + {yyerror ("'(' expected"); RECOVER;} +| NEW_TK class_type OP_TK error + {yyerror ("')' or term expected"); RECOVER;} +| NEW_TK class_type OP_TK argument_list error + {yyerror ("')' expected"); RECOVER;} +| something_dot_new error + {YYERROR_NOW; yyerror ("Identifier expected"); RECOVER;} +| something_dot_new identifier error + {yyerror ("'(' expected"); RECOVER;} +; + +something_dot_new: /* Added, not part of the specs. */ + name DOT_TK NEW_TK +| primary DOT_TK NEW_TK +; + +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_expression: + 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, ctxp->osb_number); } +| NEW_TK class_or_interface_type dim_exprs dims + { $$ = build_newarray_node ($2, $3, ctxp->osb_number); } + /* Added, JDK1.1 anonymous array. Initial documentation rule + modified */ +| NEW_TK class_or_interface_type dims array_initializer +{$$ = $2;} +| NEW_TK primitive_type dims array_initializer +{$$ = $2;} +| 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 + { + 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 + { ctxp->osb_number = 1; } +| dims OSB_TK CSB_TK + { ctxp->osb_number++; } +| dims OSB_TK error + { yyerror ("']' expected"); RECOVER;} +; + +field_access: + primary DOT_TK identifier + { $$ = make_qualified_primary ($1, $3, $2.location); } +| SUPER_TK DOT_TK identifier + { + tree super_wfl = + build_wfl_node (super_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (super_wfl) = $1.location; + $$ = 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 + { + 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 + { + tree invok = build_method_invocation ($3, $5); + $$ = make_qualified_primary ($1, invok, $2.location); + } +| SUPER_TK DOT_TK identifier OP_TK CP_TK + { + tree invok; + tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = $1.location; + invok = build_method_invocation ($3, NULL_TREE); + $$ = make_qualified_primary (wfl, invok, $2.location); + } +| SUPER_TK DOT_TK identifier OP_TK argument_list CP_TK + { + tree invok; + tree wfl = build_wfl_node (super_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = $1.location; + invok = build_method_invocation ($3, $5); + $$ = make_qualified_primary (wfl, invok, $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); } +| 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); + } +; + +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); } +; + +unary_expression: + pre_increment_expression +| pre_decrement_expression +| PLUS_TK unary_expression + {$$ = build_unaryop ($1.token, $1.location, $2); } +| MINUS_TK unary_expression + {$$ = build_unaryop ($1.token, $1.location, $2); } +| unary_expression_not_plus_minus +| PLUS_TK error + {yyerror ("Missing term"); RECOVER} +| 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; + while (ctxp->osb_number--) + 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 + { + char *ptr; + while (ctxp->osb_number--) + obstack_1grow (&temporary_obstack, '['); + obstack_grow0 (&temporary_obstack, + IDENTIFIER_POINTER (EXPR_WFL_NODE ($2)), + IDENTIFIER_LENGTH (EXPR_WFL_NODE ($2))); + 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 + { + if (ctxp->prevent_ese != lineno) + 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 +| 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 +| 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 + { + if (ctxp->prevent_ese != lineno) + 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 +; + +%% + + +#include "lex.c" + +/* 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; + +/* Create a new parser context and make it the current one. */ + +void +java_push_parser_context () +{ + struct parser_ctxt *new = + (struct parser_ctxt *)malloc(sizeof (struct parser_ctxt)); + + bzero (new, sizeof (struct parser_ctxt)); + new->next = ctxp; + ctxp = new; + if (ctxp->next) + ctxp->incomplete_class = ctxp->next->incomplete_class; +} + +void +java_parser_context_save_global () +{ + ctxp->finput = finput; + ctxp->lineno = lineno; + ctxp->current_class = current_class; + ctxp->filename = input_filename; + ctxp->current_function_decl = current_function_decl; +} + +void +java_parser_context_restore_global () +{ + finput = ctxp->finput; + lineno = ctxp->lineno; + current_class = ctxp->current_class; + input_filename = ctxp->filename; + current_function_decl = ctxp->current_function_decl; +} + +void +java_pop_parser_context () +{ + tree current; + struct parser_ctxt *toFree = ctxp; + struct parser_ctxt *next = ctxp->next; + + if (next) + { + next->incomplete_class = ctxp->incomplete_class; + lineno = ctxp->lineno; + finput = ctxp->finput; + current_class = ctxp->current_class; + } + + /* 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_PURPOSE (current)) = 0; + + /* And restore those of the previous context */ + if (ctxp = next) + for (current = ctxp->import_list; current; current = TREE_CHAIN (current)) + IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (TREE_PURPOSE (current)) = 1; + + free (toFree); +} + +static int do_warning = 0; + +void +yyerror (msg) + char *msg; +{ + static java_lc elc; + static int prev_lineno; + static char *prev_msg; + + int i, save_lineno; + char *remainder, *code_from_source; + extern struct obstack temporary_obstack; + + if (!force_error && prev_lineno == lineno) + return; + + /* Save current error location but report latter, when the context is + richer. */ + if (ctxp->java_error_flag == 0) + { + ctxp->java_error_flag = 1; + elc = ctxp->elc; + /* Do something to use the previous line if we're reaching the + end of the file... */ +#ifdef VERBOSE_SKELETON + printf ("* Error detected (%s)\n", (msg ? msg : "(null)")); +#endif + return; + } + + /* Ignore duplicate message on the same line. BTW, this is dubious. FIXME */ + if (!force_error && msg == prev_msg && prev_lineno == elc.line) + return; + + ctxp->java_error_flag = 0; + if (do_warning) + java_warning_count++; + else + java_error_count++; + + if (elc.col == 0 && msg[1] == ';') + { + elc.col = ctxp->p_line->char_col-1; + elc.line = ctxp->p_line->lineno; + } + + save_lineno = lineno; + prev_lineno = lineno = elc.line; + prev_msg = msg; + + code_from_source = java_get_line_col (ctxp->filename, elc.line, elc.col); + obstack_grow0 (&temporary_obstack, + code_from_source, strlen (code_from_source)); + remainder = obstack_finish (&temporary_obstack); + if (do_warning) + warning ("%s.\n%s", msg, remainder); + else + error ("%s.\n%s", msg, 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. */ + ctxp->prevent_ese = lineno = save_lineno; +} + +static void +parse_error (msg) + char *msg; +{ + java_error (NULL); + java_error (msg); +} + +/* Issue an error message at a current source line CL */ + +static void +parse_error_context VPROTO ((tree cl, char *msg, ...)) +{ +#ifndef __STDC__ + tree cl; + char *msg; +#endif + char buffer [4096]; + va_list ap; + + VA_START (ap, msg); +#ifndef __STDC__ + cl = va_arg (ap, tree); + msg = va_arg (ap, char *); +#endif + vsprintf (buffer, msg, ap); + + force_error = 1; + ctxp->elc.line = EXPR_WFL_LINENO (cl); + ctxp->elc.col = (EXPR_WFL_COLNO (cl) == 0xfff ? -1 : EXPR_WFL_COLNO (cl)); + + parse_error (buffer); + force_error = 0; +} + +/* Issue a warning at a current source line CL */ + +static void +parse_warning_context VPROTO ((tree cl, char *msg, ...)) +{ +#ifndef __STDC__ + tree cl; + char *msg; +#endif + char buffer [4096]; + va_list ap; + + VA_START (ap, msg); +#ifndef __STDC__ + cl = va_arg (ap, tree); + msg = va_arg (ap, char *); +#endif + vsprintf (buffer, msg, ap); + + force_error = do_warning = 1; + ctxp->elc.line = EXPR_WFL_LINENO (cl); + ctxp->elc.col = (EXPR_WFL_COLNO (cl) == 0xfff ? -1 : EXPR_WFL_COLNO (cl)); + + parse_error (buffer); + do_warning = force_error = 0; +} + +void +java_report_errors () +{ + if (java_error_count) + fprintf (stderr, "%d error%s", + java_error_count, (java_error_count == 1 ? "" : "s")); + if (java_warning_count) + fprintf (stderr, "%s%d warning%s", (java_error_count ? ", " : ""), + java_warning_count, (java_warning_count == 1 ? "" : "s")); + if (java_error_count || java_warning_count) + putc ('\n', stderr); +} + +static char * +java_accstring_lookup (flags) + int flags; +{ + static char buffer [80]; +#define COPY_RETURN(S) {strcpy (buffer, S); return buffer;} + + /* Access modifier looked-up first for easier report on forbidden + access. */ + if (flags & ACC_PUBLIC) COPY_RETURN ("public"); + if (flags & ACC_PRIVATE) COPY_RETURN ("private"); + if (flags & ACC_PROTECTED) COPY_RETURN ("protected"); + if (flags & ACC_STATIC) COPY_RETURN ("static"); + if (flags & ACC_FINAL) COPY_RETURN ("final"); + if (flags & ACC_SYNCHRONIZED) COPY_RETURN ("synchronized"); + if (flags & ACC_VOLATILE) COPY_RETURN ("volatile"); + if (flags & ACC_TRANSIENT) COPY_RETURN ("transient"); + if (flags & ACC_NATIVE) COPY_RETURN ("native"); + if (flags & ACC_INTERFACE) COPY_RETURN ("interface"); + if (flags & ACC_ABSTRACT) COPY_RETURN ("abstract"); + + buffer [0] = '\0'; + return buffer; +#undef COPY_RETURN +} + +static void +redefinition_error (context, id, decl, cl) + char *context; + tree id, decl, cl; +{ + parse_error_context (cl, "%s `%s' already defined in %s:%d", + context, IDENTIFIER_POINTER (id), + DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); + /* Here we should point out where its redefined. It's a unicode. FIXME */ +} + +/* Build something that the type identifier resolver will identify as + being an array to an unresolved type. TYPE_WFL is a WFL on a + identifier. */ + +static tree +build_unresolved_array_type (type_or_wfl) + tree type_or_wfl; +{ + char *ptr; + + /* TYPE_OR_WFL might be an array on a primitive type. In this case, + just create a array type */ + if (TREE_CODE (type_or_wfl) == RECORD_TYPE) + { + tree type = build_java_array_type (type_or_wfl, -1); + CLASS_LOADED_P (type) = CLASS_LOADED_P (type_or_wfl); + return type; + } + + obstack_1grow (&temporary_obstack, '['); + obstack_grow0 (&temporary_obstack, + IDENTIFIER_POINTER (EXPR_WFL_NODE (type_or_wfl)), + IDENTIFIER_LENGTH (EXPR_WFL_NODE (type_or_wfl))); + ptr = obstack_finish (&temporary_obstack); + return build_expr_wfl (get_identifier (ptr), + EXPR_WFL_FILENAME (type_or_wfl), + EXPR_WFL_LINENO (type_or_wfl), + EXPR_WFL_COLNO (type_or_wfl)); +} + +/* Check modifiers. If one doesn't fit, retrieve it in its declaration line + and point it out. */ + +static void +check_modifiers (message, value, mask) + char *message; + int value; + int mask; +{ + /* Should point out the one that don't fit. ASCII/unicode, + going backward. FIXME */ + if (value & ~mask) + { + int i, remainder = value & ~mask; + for (i = 0; i <= 10; i++) + if ((1 << i) & remainder) + parse_error_context (ctxp->modifier_ctx [i], message, + java_accstring_lookup (1 << i)); + } +} + +static void +parser_add_interface (class_decl, interface_decl, wfl) + tree class_decl, interface_decl, wfl; +{ + if (maybe_add_interface (TREE_TYPE (class_decl), TREE_TYPE (interface_decl))) + parse_error_context (wfl, "Interface `%s' repeated", + IDENTIFIER_POINTER (DECL_NAME (interface_decl))); +} + +/* Bulk of common class/interface checks. Return 1 if an error was + encountered. TAG is 0 for a class, 1 for an interface. */ + +static int +check_class_interface_creation (is_interface, flags, raw_name, qualified_name, decl, cl) + int is_interface, flags; + tree raw_name, qualified_name, decl, cl; +{ + tree node; + + if (!quiet_flag) + fprintf (stderr, " %s %s", (is_interface ? "interface" : "class"), + IDENTIFIER_POINTER (qualified_name)); + + /* Scope of an interface/class type name: + - Can't be imported by a single type import + - Can't already exists in the package */ + if (IS_A_SINGLE_IMPORT_CLASSFILE_NAME_P (raw_name) + && (node = find_name_in_single_imports (raw_name))) + { + parse_error_context + (cl, "%s name `%s' clashes with imported type `%s'", + (is_interface ? "Interface" : "Class"), + IDENTIFIER_POINTER (raw_name), IDENTIFIER_POINTER (node)); + return 1; + } + if (decl && CLASS_COMPLETE_P (decl)) + { + redefinition_error ((is_interface ? "Interface" : "Class"), + qualified_name, decl, cl); + return 1; + } + + /* If public, file name should match class/interface name */ + if (flags & ACC_PUBLIC) + { + char *f; + + /* Contains OS dependent assumption on path separator. FIXME */ + for (f = &input_filename [strlen (input_filename)]; + f != input_filename && f[0] != '/'; f--); + if (f[0] == '/') + f++; + if (strncmp (IDENTIFIER_POINTER (raw_name), + f , IDENTIFIER_LENGTH (raw_name)) || + f [IDENTIFIER_LENGTH (raw_name)] != '.') + parse_error_context (cl, "Public %s `%s' must be defined in a file " + "called `%s.java'", + (is_interface ? "interface" : "class"), + IDENTIFIER_POINTER (qualified_name), + IDENTIFIER_POINTER (raw_name)); + } + + check_modifiers ((is_interface ? + "Illegal modifier `%s' for interface declaration" : + "Illegal modifier `%s' for class declaration"), flags, + (is_interface ? INTERFACE_MODIFIERS : CLASS_MODIFIERS)); + return 0; +} + +/* If DECL is NULL, create and push a new DECL, record the current + line CL and do other maintenance things. */ + +static tree +maybe_create_class_interface_decl (decl, qualified_name, cl) + tree decl, qualified_name, cl; +{ + if (decl) + DECL_ARTIFICIAL (decl) = 1; /* FIXME */ + else + decl = push_class (make_class (), qualified_name); + + /* Take care of the file and line business */ + DECL_SOURCE_FILE (decl) = EXPR_WFL_FILENAME (cl); + DECL_SOURCE_LINE (decl) = EXPR_WFL_LINENO (cl); + CLASS_FROM_SOURCE_P (TREE_TYPE (decl)) = 1; + + ctxp->current_parsed_class = decl; + + /* Link the declaration to the already seen ones */ + TREE_CHAIN (decl) = ctxp->class_list; + ctxp->class_list = decl; + /* Install a new dependency list element */ + create_jdep_list (ctxp); + + SOURCE_FRONTEND_DEBUG (("Defining class/interface %s", + IDENTIFIER_POINTER (qualified_name))); + return decl; +} + +static void +add_superinterfaces (decl, interface_list) + tree decl, interface_list; +{ + tree node; + /* Superinterface(s): if present and defined, parser_check_super_interface () + takes care of ensuring that: + - This is an accessible interface type, + - Circularity detection. + parser_add_interface is then called. If present but not defined, + the check operation is delayed until the super interface gets + defined. */ + for (node = interface_list; node; node = TREE_CHAIN (node)) + { + tree current = TREE_PURPOSE (node), interface_decl; + if ((interface_decl = IDENTIFIER_CLASS_VALUE (EXPR_WFL_NODE (current)))) + { + if (!parser_check_super_interface (interface_decl, decl, current)) + parser_add_interface (decl, interface_decl, current); + } + else + register_incomplete_type (JDEP_INTERFACE, + current, decl, NULL_TREE); + } +} + +/* Create an interface in pass1 and return its decl. Return the + interface's decl in pass 2. */ + +static tree +create_interface (flags, id, super) + int flags; + tree id, super; +{ + int chk; + tree raw_name = EXPR_WFL_NODE (id); + tree q_name = parser_qualified_classname (id); + tree decl = IDENTIFIER_CLASS_VALUE (q_name); + + EXPR_WFL_NODE (id) = q_name; /* Keep source location, even if refined. */ + + /* Basic checks: scope, redefinition, modifiers */ + if (check_class_interface_creation (1, flags, raw_name, q_name, decl, id)) + return NULL_TREE; + + /* Interface modifiers check + - public/abstract allowed (already done at that point) + - abstract is obsolete (comes first, it's a warning, or should be) + - Can't use twice the same (checked in the modifier rule) */ + if (flags & ACC_ABSTRACT) + parse_warning_context + (MODIFIER_WFL (ABSTRACT_TK), + "Obsolete use of `abstract' modifier. Interface `%s' is implicitely " + "abstract", IDENTIFIER_POINTER (raw_name)); + if (flags & ACC_PUBLIC && flags & ACC_ABSTRACT) + parse_error_context + (MODIFIER_WFL (ABSTRACT_TK), + "Can't specify both `public' and `abstract' modifiers in the " + "definition of interface `%s'", IDENTIFIER_POINTER (raw_name)); + + /* Create a new decl if DECL is NULL, otherwise fix it */ + decl = maybe_create_class_interface_decl (decl, q_name, id); + + /* Set super info and mark the class a complete */ + set_super_info (ACC_ABSTRACT | ACC_INTERFACE | flags, TREE_TYPE (decl), + object_type_node, ctxp->interface_number); + ctxp->interface_number = 0; + CLASS_COMPLETE_P (decl) = 1; + add_superinterfaces (decl, super); + + return decl; +} + +/* Create an class in pass1 and return its decl. Return class + interface's decl in pass 2. */ + +static tree +create_class (flags, id, super, interfaces) + int flags; + tree id, super, interfaces; +{ + int chk; + tree raw_name = EXPR_WFL_NODE (id); + tree class_id, decl; + tree super_decl = NULL, super_decl_type; + + class_id = parser_qualified_classname (id); + decl = IDENTIFIER_CLASS_VALUE (class_id); + EXPR_WFL_NODE (id) = class_id; + + /* Basic check: scope, redefinition, modifiers */ + if (check_class_interface_creation (0, flags, raw_name, class_id, decl, id)) + return NULL_TREE; + + /* Class modifier check: + - Allowed modifier (already done at that point) + - abstract AND final forbidden + - Public classes defined in the correct file */ + if ((flags & ACC_ABSTRACT) && (flags & ACC_FINAL)) + parse_error_context (id, "Class `%s' can't be declared both abstract " + "and final", IDENTIFIER_POINTER (raw_name)); + + /* Create a new decl if DECL is NULL, otherwise fix it */ + decl = maybe_create_class_interface_decl (decl, class_id, id); + + /* If SUPER exists, use it, otherwise use Object */ + if (super) + { + /* Can't extend java.lang.Object */ + if (TREE_TYPE (IDENTIFIER_CLASS_VALUE (class_id)) == object_type_node) + { + parse_error_context (id, "Can't extend `java.lang.Object'"); + return NULL_TREE; + } + + /* The class is known and exists if there is a decl. Otherwise, + postpone the operation and do it later. */ + super_decl = IDENTIFIER_CLASS_VALUE (EXPR_WFL_NODE (super)); + if (super_decl) + { + parser_check_super (super_decl, decl, id); + super_decl_type = TREE_TYPE (super_decl); + } + else + super_decl_type = + register_incomplete_type (JDEP_SUPER, super, decl, NULL_TREE); + } + else if (TREE_TYPE (decl) != object_type_node) + super_decl_type = object_type_node; + /* We're defining java.lang.Object */ + else + super_decl_type = NULL_TREE; + + /* Set super info and mark the class a complete */ + set_super_info (flags, TREE_TYPE (decl), super_decl_type, + ctxp->interface_number); + ctxp->interface_number = 0; + CLASS_COMPLETE_P (decl) = 1; + add_superinterfaces (decl, interfaces); + + return decl; +} + +/* Can't use lookup_field () since we don't want to load the class and + can't set the CLASS_LOADED_P flag */ + +static tree +find_field (class, name) + tree class; + tree name; +{ + tree decl; + for (decl = TYPE_FIELDS (class); decl; decl = TREE_CHAIN (decl)) + { + if (DECL_NAME (decl) == name) + return decl; + } + return NULL_TREE; +} + +/* Wrap around lookup_field that doesn't potentially upset the value + of CLASS */ + +static tree +lookup_field_wrapper (class, name) + tree class, name; +{ + tree type = class; + return lookup_field (&type, name); +} + +/* Find duplicate field within the same class declarations and report + the error */ + +static int +duplicate_declaration_error (class, new_field_name, new_type, cl) + tree class, new_field_name, new_type, cl; +{ + /* This might be modified to work with method decl as well */ + tree decl = find_field (TREE_TYPE (ctxp->current_parsed_class), + new_field_name); + if (decl) + { + char *t1 = strdup ((char *)lang_printable_name (new_type, 1)); + char *t2 = + strdup ((TREE_CODE (TREE_TYPE (decl)) == TREE_LIST ? + IDENTIFIER_POINTER (TYPE_NAME + (TREE_PURPOSE (TREE_TYPE (decl)))) : + (char *)lang_printable_name (TREE_TYPE (decl), 1))); + parse_error_context + (cl , "Duplicate variable declaration: `%s %s' was `%s %s' (%s:%d)", + t1, IDENTIFIER_POINTER (new_field_name), + t2, IDENTIFIER_POINTER (DECL_NAME (decl)), + DECL_SOURCE_FILE (decl), DECL_SOURCE_LINE (decl)); + free (t1); + free (t2); + return 0; + } + return 1; +} + +/* Field registration routine. If TYPE doesn't exist, field + declarations are linked to the undefined TYPE dependency list, to + be later resolved in java_complete_class () */ + +static void +register_fields (flags, type, variable_list) + int flags; + tree type, variable_list; +{ + tree current, type_decl, returned_type; + tree class_type = TREE_TYPE (ctxp->current_parsed_class); + int saved_lineno = lineno; + int must_chain = 0; + tree wfl = NULL_TREE; + + /* If we're adding fields to interfaces, those fields are public, + static, final */ + if (CLASS_INTERFACE (TYPE_NAME (class_type))) + { + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (PUBLIC_TK), + flags, ACC_PUBLIC, + "%s", "interface field(s)"); + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (STATIC_TK), + flags, ACC_STATIC, + "%s", "interface field(s)"); + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (FINAL_TK), + flags, ACC_FINAL, "%s", "interface field(s)"); + check_modifiers ("Illegal interface member modifier `%s'", flags, + INTERFACE_FIELD_MODIFIERS); + flags |= (ACC_PUBLIC | ACC_STATIC | ACC_FINAL); + } + + if (unresolved_type_p (type, &returned_type)) + { + if (returned_type) + type = returned_type; + else + { + wfl = type; + type = obtain_incomplete_type (type); + must_chain = 1; + } + } + + for (current = variable_list; current; current = TREE_CHAIN (current)) + { + tree cl = TREE_PURPOSE (current); + tree init = TREE_VALUE (current); + tree current_name = EXPR_WFL_NODE (cl); + + if (duplicate_declaration_error (class_type, current_name, type, cl)) + { + tree field_decl; + lineno = EXPR_WFL_LINENO (cl); + field_decl = add_field (class_type, current_name, type, flags); + + /* Check if we must chain. */ + if (must_chain) + register_incomplete_type (JDEP_FIELD, wfl, field_decl, type); + + /* Default value of a static field is 0 and it is considered + initialized. */ + if (flags & ACC_STATIC) + INITIALIZED_P (field_decl) = 1; + + /* If we have an initialization value tied to the field */ + if (init) + { + /* The field is declared static */ + if (flags & ACC_STATIC) + { + /* FIXME */ + if (flags & ACC_FINAL) + ; + /* Otherwise, the field should be initialized in + . This field is remembered so we can + generate later. */ + else + { + INITIALIZED_P (field_decl) = 1; + TREE_CHAIN (init) = ctxp->static_initialized; + ctxp->static_initialized = init; + } + } + /* A non-static field declared with an immediate + initialization is to be initialized in , if + any. This field is remembered to be processed at the + time of the generation of . */ + else + { + TREE_CHAIN (init) = ctxp->non_static_initialized; + ctxp->non_static_initialized = init; + } + } + } + } + lineno = saved_lineno; +} + +/* Check whether it is necessary to generate a for the class + we just parsed. */ + +static void +maybe_generate_clinit () +{ + int saved_lineno; + tree meth, mdecl, c; + tree cclass, class_wfl; + + if (!ctxp->static_initialized || java_error_count) + return; + + cclass = TREE_TYPE (ctxp->current_parsed_class); + class_wfl = build_expr_wfl (DECL_NAME (TYPE_NAME (cclass)), + input_filename, 0, 0); + + saved_lineno = lineno; + lineno = 0; + meth = make_node (FUNCTION_TYPE); + TREE_TYPE (meth) = void_type_node; + TYPE_ARG_TYPES (meth) = NULL_TREE; + mdecl = add_method (cclass, ACC_STATIC, clinit_identifier_node, + build_java_signature (meth)); + lineno = saved_lineno; + + DECL_SOURCE_LINE (mdecl) = 1; + DECL_SOURCE_LINE_MERGE (mdecl, 1); + source_start_java_method (mdecl); + enter_block (); + + /* Keep initialization in order to enforce 8.5 */ + ctxp->static_initialized = nreverse (ctxp->static_initialized); + + /* We process the list of assignment we produced as the result of + the declaration of initialized static field and add them as + statement to the method. */ + for (c = ctxp->static_initialized; c; c = TREE_CHAIN (c)) + { + /* We build the assignment expression that will initialize the + field to its value. There are strict rules on static + initializers (8.5). FIXME */ + java_method_add_stmt (mdecl, c); + } + + BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = exit_block (); + exit_block (); + ctxp->static_initialized = NULL_TREE; +} + +/* Shared accros method_declarator and method_header to remember the + patch stage that was reached during the declaration of the method. + A method DECL is built differently is there is no patch + (JDEP_NO_PATCH) or a patch (JDEP_METHOD or JDEP_METHOD_RETURN) + pending on the currently defined method. */ + +static int patch_stage; + +/* Check the method declaration and add the method to its current + class. If the argument list is known to contain incomplete types, + the method is partially added and the registration will be resume + once the method arguments resolved */ + +static tree +method_header (flags, type, mdecl, throws) + int flags; + tree type, mdecl, throws; +{ + tree meth = TREE_VALUE (mdecl); + tree id = TREE_PURPOSE (mdecl); + tree this_class = TREE_TYPE (ctxp->current_parsed_class); + tree handle_class = CLASS_TO_HANDLE_TYPE (this_class); + tree meth_name, returned_type; + int saved_lineno; + + check_modifiers_consistency (flags); + + /* There are some forbidden modifiers for an abstract method and its + class must be abstract as well. */ + if (flags & ACC_ABSTRACT) + { + ABSTRACT_CHECK (flags, ACC_PRIVATE, id, "Private"); + ABSTRACT_CHECK (flags, ACC_STATIC, id, "Static"); + ABSTRACT_CHECK (flags, ACC_FINAL, id, "Final"); + ABSTRACT_CHECK (flags, ACC_NATIVE, id, "Native"); + ABSTRACT_CHECK (flags, ACC_SYNCHRONIZED,id, "Synchronized"); + if (!CLASS_ABSTRACT (TYPE_NAME (this_class))) + parse_error_context + (id, "Class `%s' must be declared abstract to define abstract " + "method `%s'", + IDENTIFIER_POINTER (DECL_NAME (ctxp->current_parsed_class)), + IDENTIFIER_POINTER (EXPR_WFL_NODE (id))); + } + + + /* Method declared within the scope of an interface are implicitly + abstract and public. Conflicts with other erroneously provided + modifiers are check right after. */ + + if (CLASS_INTERFACE (TYPE_NAME (this_class))) + { + /* If FLAGS isn't set because of a modifier, turn the + corresponding modifier WFL to NULL so we issue a warning on + the obsolete use of the modifier */ + if (!(flags & ACC_PUBLIC)) + MODIFIER_WFL (PUBLIC_TK) = NULL; + if (!(flags & ACC_ABSTRACT)) + MODIFIER_WFL (ABSTRACT_TK) = NULL; + flags |= ACC_PUBLIC; + flags |= ACC_ABSTRACT; + } + + /* Modifiers context reset moved up, so abstract method declaration + modifiers can be later checked. */ + + meth_name = EXPR_WFL_NODE (id); + + if (unresolved_type_p (type, &returned_type)) + { + if (returned_type) + TREE_TYPE (meth) = returned_type; + else + { + patch_stage = JDEP_METHOD_RETURN; + TREE_TYPE (meth) = + register_incomplete_type (patch_stage, type, id, NULL_TREE); + } + } + else + TREE_TYPE (meth) = type; + + saved_lineno = lineno; + /* When defining an abstract or interface method, the curly + bracket at level 1 doesn't exist because there is no function + body */ + lineno = (ctxp->first_ccb_indent1 ? ctxp->first_ccb_indent1 : + EXPR_WFL_LINENO (id)); + + if (patch_stage) /* includes ret type and/or all args */ + { + jdep *jdep; + meth = add_method_1 (this_class, flags, meth_name, meth); + /* Patch for the return type */ + if (patch_stage == JDEP_METHOD_RETURN) + { + jdep = CLASSD_LAST (ctxp->classd_list); + JDEP_GET_PATCH (jdep) = &TREE_TYPE (TREE_TYPE (meth)); + } + /* This is the stop JDEP. METH allows the function's signature + to be computed. */ + register_incomplete_type (JDEP_METHOD_END, NULL_TREE, meth, NULL_TREE); + } + else + { + tree signature = build_java_signature (meth); + tree arg, orig_arg; + /* Save original argument list, including argument's names */ + orig_arg = TYPE_ARG_TYPES (meth); + /* Add the method to its class */ + meth = add_method (this_class, flags, meth_name, signature); + /* Fix the method argument list so we have the argument name + information */ + arg = TYPE_ARG_TYPES (TREE_TYPE (meth)); + if (TREE_CODE (TREE_TYPE (meth)) == METHOD_TYPE) + { + TREE_PURPOSE (arg) = this_identifier_node; + arg = TREE_CHAIN (arg); + } + while (orig_arg) + { + TREE_PURPOSE (arg) = TREE_PURPOSE (orig_arg); + orig_arg = TREE_CHAIN (orig_arg); + arg = TREE_CHAIN (arg); + } + } + DECL_MAX_LOCALS (meth) = ctxp->formal_parameter_number+1; + lineno = saved_lineno; + /* We set the DECL_NAME to ID so we can track the location where + the function was declared. This allow us to report + redefinition error accurately. When method are verified, + DECL_NAME is reinstalled properly (using the content of the + WFL node ID) (see check_method_redefinition). We don't do that + when Object is being defined. */ + if (TREE_TYPE (ctxp->current_parsed_class) != object_type_node) + DECL_NAME (meth) = id; + return meth; +} + +/* Check modifiers that can be declared but exclusively */ + +static void +check_modifiers_consistency (flags) + int flags; +{ + int acc_count = 0; + tree cl = NULL_TREE; + + THIS_MODIFIER_ONLY (flags, ACC_PUBLIC, 0, acc_count, cl); + THIS_MODIFIER_ONLY (flags, ACC_PRIVATE, 1, acc_count, cl); + THIS_MODIFIER_ONLY (flags, ACC_PROTECTED, 2, acc_count, cl); + if (acc_count > 1) + parse_error_context + (cl, "Inconsistent member declaration. At most one of `public', " + "`private', or `protected' may be specified"); +} + +/* Check the methode header METH for abstract specifics features */ + +static void +check_abstract_method_header (meth) + tree meth; +{ + int flags = get_access_flags_from_decl (meth); + /* DECL_NAME might still be a WFL node */ + tree name = (TREE_CODE (DECL_NAME (meth)) == EXPR_WITH_FILE_LOCATION ? + EXPR_WFL_NODE (DECL_NAME (meth)) : DECL_NAME (meth)); + + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (ABSTRACT_TK), flags, + ACC_ABSTRACT, "abstract method `%s'", + IDENTIFIER_POINTER (name)); + OBSOLETE_MODIFIER_WARNING (MODIFIER_WFL (PUBLIC_TK), flags, + ACC_PUBLIC, "abstract method `%s'", + IDENTIFIER_POINTER (name)); + + check_modifiers ("Illegal modifier `%s' for interface method", + flags, INTERFACE_METHOD_MODIFIERS); +} + +/* Create a FUNCTION_TYPE node and start augmenting it with the + declared function arguments. Arguments type that can't be resolved + are left as they are, but the returned node is marked as containing + incomplete types. */ + +static tree +method_declarator (id, list) + tree id, list; +{ + tree arg_types = NULL_TREE, current, node; + tree meth = make_node (FUNCTION_TYPE); + jdep *jdep; + int incomplete = 0; + + patch_stage = JDEP_NO_PATCH; + + for (current = list; current; current = TREE_CHAIN (current)) + { + tree wfl_name = TREE_PURPOSE (current); + tree type = TREE_VALUE (current); + tree name = EXPR_WFL_NODE (wfl_name); + tree patchable_type = NULL_TREE, already; + tree arg_node, returned_type; + + /* Check redefinition */ + for (already = arg_types; already; already = TREE_CHAIN (already)) + if (TREE_PURPOSE (already) == name) + { + parse_error_context + (wfl_name, "Variable `%s' is used more than once in the " + "argument list of method `%s'", IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (EXPR_WFL_NODE (id))); + break; + } + + /* If we've an incomplete argument type, we know there is a location + to patch when the type get resolved, later. */ + jdep = NULL; + if (unresolved_type_p (type, &returned_type)) + { + if (returned_type) + type = returned_type; + else + { + patch_stage = JDEP_METHOD; + type = register_incomplete_type (patch_stage, type, + wfl_name, NULL_TREE); + jdep = CLASSD_LAST (ctxp->classd_list); + JDEP_MISC (jdep) = id; + } + } + /* The argument node: a name and a (possibly) incomplete type */ + arg_node = build_tree_list (name, type); + if (jdep) + JDEP_GET_PATCH (jdep) = &TREE_VALUE (arg_node); + TREE_CHAIN (arg_node) = arg_types; + arg_types = arg_node; + } + TYPE_ARG_TYPES (meth) = nreverse (arg_types); + node = build_tree_list (id, meth); + return node; +} + +static int +unresolved_type_p (wfl, returned) + tree wfl; + tree *returned; + +{ + if (TREE_CODE (wfl) == EXPR_WITH_FILE_LOCATION) + { + tree decl = IDENTIFIER_CLASS_VALUE (EXPR_WFL_NODE (wfl)); + if (returned) + *returned = (decl ? TREE_TYPE (decl) : NULL_TREE); + return 1; + } + if (returned) + *returned = wfl; + return 0; +} + +/* From NAME, build a qualified identifier node using the + qualification from the current package definition. */ + +static tree +parser_qualified_classname (name) + tree name; +{ + if (ctxp->package) + return merge_qualified_name (ctxp->package, EXPR_WFL_NODE (name)); + else + return EXPR_WFL_NODE (name); +} + +/* Called once the type a interface extends is resolved. Returns 0 if + everything is OK. */ + +static int +parser_check_super_interface (super_decl, this_decl, this_wfl) + tree super_decl, this_decl, this_wfl; +{ + tree super_type = TREE_TYPE (super_decl); + + /* Has to be an interface */ + if (!CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (super_decl)))) + { + parse_error_context + (this_wfl, "Can't use %s `%s' to implement/extend %s `%s'", + (TYPE_ARRAY_P (super_type) ? "array" : "class"), + IDENTIFIER_POINTER (DECL_NAME (super_decl)), + (CLASS_INTERFACE (TYPE_NAME (TREE_TYPE (this_decl))) ? + "interface" : "class"), + IDENTIFIER_POINTER (DECL_NAME (this_decl))); + return 1; + } + + /* Check scope: same package OK, other package: OK if public */ + if (check_pkg_class_access (DECL_NAME (super_decl), lookup_cl (this_decl))) + return 1; + + SOURCE_FRONTEND_DEBUG (("Completing interface %s with %s", + IDENTIFIER_POINTER (DECL_NAME (this_decl)), + IDENTIFIER_POINTER (DECL_NAME (super_decl)))); + return 0; +} + +/* Makes sure that SUPER_DECL is suitable to extend THIS_DECL. Returns + 0 if everthing is OK. */ + +static int +parser_check_super (super_decl, this_decl, wfl) + tree super_decl, this_decl, wfl; +{ + tree this_type = TREE_TYPE (this_decl); + tree super_type = TREE_TYPE (super_decl); + + /* SUPER should be a CLASS (neither an array nor an interface) */ + if (TYPE_ARRAY_P (super_type) || CLASS_INTERFACE (TYPE_NAME (super_type))) + { + parse_error_context + (wfl, "Class `%s' can't subclass %s `%s'", + IDENTIFIER_POINTER (DECL_NAME (this_decl)), + (CLASS_INTERFACE (TYPE_NAME (super_type)) ? "interface" : "array"), + IDENTIFIER_POINTER (DECL_NAME (super_decl))); + return 1; + } + + if (CLASS_FINAL (TYPE_NAME (super_type))) + { + parse_error_context (wfl, "Can't subclass final classes: %s", + IDENTIFIER_POINTER (DECL_NAME (super_decl))); + return 1; + } + + /* Check scope: same package OK, other package: OK if public */ + if (check_pkg_class_access (DECL_NAME (super_decl), wfl)) + return 1; + + SOURCE_FRONTEND_DEBUG (("Completing class %s with %s", + IDENTIFIER_POINTER (DECL_NAME (this_decl)), + IDENTIFIER_POINTER (DECL_NAME (super_decl)))); + return 0; +} + +/* Create a new dependency list and link it (in a LIFO manner) to the + CTXP list of type dependency list. */ + +static void +create_jdep_list (ctxp) + struct parser_ctxt *ctxp; +{ + jdeplist *new = malloc (sizeof (jdeplist)); + + if (!new) + fatal ("Can't alloc jdeplist - create_jdep_list"); + + new->first = new->last = NULL; + new->next = ctxp->classd_list; + ctxp->classd_list = new; +} + +static jdeplist * +reverse_jdep_list (ctxp) + struct parser_ctxt *ctxp; +{ + register jdeplist *prev = NULL, *current, *next; + for (current = ctxp->classd_list; current; current = next) + { + next = current->next; + current->next = prev; + prev = current; + } + return prev; +} + +/* Create a fake pointer based on the ID stored in the WFL */ + +static tree +obtain_incomplete_type (wfl) + tree wfl; +{ + tree ptr; + tree name = EXPR_WFL_NODE (wfl); + + for (ptr = ctxp->incomplete_class; ptr; ptr = TREE_CHAIN (ptr)) + if (TYPE_NAME (TREE_PURPOSE (ptr)) == name) + break; + + if (!ptr) + { + tree core; + push_obstacks (&permanent_obstack, &permanent_obstack); + BUILD_PTR_FROM_NAME (core, name); + ptr = build_tree_list (core, NULL_TREE); + pop_obstacks (); + TREE_CHAIN (ptr) = ctxp->incomplete_class; + ctxp->incomplete_class = ptr; + } + + return ptr; +} + +/* Register a incomplete type whose name is WFL. Reuse PTR if PTR is + non NULL instead of computing a new fake type based on WFL. The new + dependency is inserted in the current type dependency list, in FIFO + manner. */ + +static tree +register_incomplete_type (kind, wfl, decl, ptr) + int kind; + tree wfl, decl, ptr; +{ + jdep *new = malloc (sizeof (jdep)); + + if (!new) + fatal ("Can't allocate new jdep - register_incomplete_type"); + if (!ptr && kind != JDEP_METHOD_END) /* JDEP_METHOD_END is a mere marker */ + ptr = obtain_incomplete_type (wfl); + + JDEP_KIND (new) = kind; + JDEP_DECL (new) = decl; + JDEP_SOLV (new) = ptr; + JDEP_WFL (new) = wfl; + JDEP_CHAIN (new) = NULL; + JDEP_MISC (new) = NULL_TREE; + JDEP_GET_PATCH (new) = (tree *)NULL; + + JDEP_INSERT (ctxp->classd_list, new); + + return ptr; +} + +void +java_check_circular_reference () +{ + tree current; + for (current = ctxp->class_list; current; current = TREE_CHAIN (current)) + { + tree type = TREE_TYPE (current); + if (CLASS_INTERFACE (TYPE_NAME (type))) + { + /* Check all interfaces this class extends */ + tree basetype_vec = TYPE_BINFO_BASETYPES (type); + int n, i; + + if (!basetype_vec) + return; + n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; i < n; i++) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + if (vec_elt && BINFO_TYPE (vec_elt) != object_type_node + && interface_of_p (type, BINFO_TYPE (vec_elt))) + parse_error_context (lookup_cl (current), + "Cyclic interface inheritance"); + } + } + else + if (inherits_from_p (CLASSTYPE_SUPER (type), type)) + parse_error_context (lookup_cl (current), + "Cyclic class inheritance"); + } +} + +void +safe_layout_class (class) + tree class; +{ + tree save_current_class = current_class; + char *save_input_filename = input_filename; + int save_lineno = lineno; + + push_obstacks (&permanent_obstack, &permanent_obstack); + layout_class (class); + pop_obstacks (); + + current_class = save_current_class; + input_filename = save_input_filename; + lineno = save_lineno; + CLASS_LOADED_P (class) = 1; +} + +static tree +jdep_resolve_class (dep) + jdep *dep; +{ + tree decl; + + if (!JDEP_RESOLVED_P (dep)) + { + decl = + resolve_class (JDEP_TO_RESOLVE (dep), JDEP_DECL (dep), JDEP_WFL (dep)); + JDEP_RESOLVED (dep, decl); + } + else + decl = JDEP_RESOLVED_DECL (dep); + + if (!decl) + { + complete_class_report_errors (dep); + return NULL_TREE; + } + return decl; +} + +/* Complete unsatisfied class declaration and their dependencies */ + +void +java_complete_class () +{ + tree current; + tree cclass; + jdeplist *cclassd; + int error_found; + + push_obstacks (&permanent_obstack, &permanent_obstack); + + /* Process imports and reverse the import on demand list */ + process_imports (); + if (ctxp->import_demand_list) + ctxp->import_demand_list = nreverse (ctxp->import_demand_list); + + /* Rever things so we have the right order */ + ctxp->class_list = nreverse (ctxp->class_list); + ctxp->classd_list = reverse_jdep_list (ctxp); + + for (cclassd = ctxp->classd_list, cclass = ctxp->class_list; + cclass && cclassd; + cclass = TREE_CHAIN (cclass), cclassd = CLASSD_CHAIN (cclassd)) + { + jdep *dep; + for (dep = CLASSD_FIRST (cclassd); dep; dep = JDEP_CHAIN (dep)) + { + tree decl; + + if (!(decl = jdep_resolve_class (dep))) + continue; + + /* Now it's time to patch */ + switch (JDEP_KIND (dep)) + { + case JDEP_SUPER: + /* Simply patch super */ + if (parser_check_super (decl, JDEP_DECL (dep), JDEP_WFL (dep))) + continue; + BINFO_TYPE (TREE_VEC_ELT (BINFO_BASETYPES (TYPE_BINFO + (TREE_TYPE (JDEP_DECL (dep)))), 0)) = TREE_TYPE (decl); + break; + + case JDEP_FIELD: + { + /* We do part of the job done in add_field */ + tree field_decl = JDEP_DECL (dep); + tree field_type = TREE_TYPE (decl); + push_obstacks (&permanent_obstack, &permanent_obstack); +#if ! JAVA_PROMOTE_TO_INT + if (TREE_CODE (field_type) == RECORD_TYPE) +#endif + field_type = promote_type (field_type); + pop_obstacks (); + TREE_TYPE (field_decl) = field_type; + SOURCE_FRONTEND_DEBUG + (("Completed field/var decl `%s' with `%s'", + IDENTIFIER_POINTER (DECL_NAME (field_decl)), + IDENTIFIER_POINTER (DECL_NAME (decl)))); + break; + } + case JDEP_METHOD: /* We start patching a method */ + case JDEP_METHOD_RETURN: + error_found = 0; + while (1) + { + if (decl) + { + tree type = promote_type (TREE_TYPE(decl)); + JDEP_APPLY_PATCH (dep, type); + SOURCE_FRONTEND_DEBUG + (((JDEP_KIND (dep) == JDEP_METHOD_RETURN ? + "Completing fct `%s' with ret type `%s'": + "Completing arg `%s' with type `%s'"), + IDENTIFIER_POINTER (EXPR_WFL_NODE + (JDEP_DECL_WFL (dep))), + IDENTIFIER_POINTER (DECL_NAME (decl)))); + } + else + error_found = 1; + dep = JDEP_CHAIN (dep); + if (JDEP_KIND (dep) == JDEP_METHOD_END) + break; + else + decl = jdep_resolve_class (dep); + } + if (!error_found) + { + tree mdecl = JDEP_DECL (dep), signature; + push_obstacks (&permanent_obstack, &permanent_obstack); + /* Recompute and reset the signature */ + signature = build_java_signature (TREE_TYPE (mdecl)); + set_java_signature (TREE_TYPE (mdecl), signature); + pop_obstacks (); + } + else + continue; + break; + + case JDEP_INTERFACE: + if (parser_check_super_interface (decl, JDEP_DECL (dep), + JDEP_WFL (dep))) + continue; + parser_add_interface (JDEP_DECL (dep), decl, JDEP_WFL (dep)); + break; + + case JDEP_VARIABLE: + JDEP_APPLY_PATCH (dep, promote_type (TREE_TYPE (decl))); + SOURCE_FRONTEND_DEBUG + (("Completing variable `%s' with type `%s'", + (TREE_CODE (JDEP_DECL_WFL (dep)) == EXPR_WITH_FILE_LOCATION ? + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep))) : + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL_WFL (dep)))), + IDENTIFIER_POINTER (DECL_NAME (decl)))); + break; + + case JDEP_TYPE: + JDEP_APPLY_PATCH (dep, TREE_TYPE (decl)); + SOURCE_FRONTEND_DEBUG + (("Completing a random type dependency on a '%s' node", + tree_code_name [TREE_CODE (JDEP_DECL (dep))])); + break; + + case JDEP_PARM: + JDEP_APPLY_PATCH (dep, promote_type (TREE_TYPE (decl))); + SOURCE_FRONTEND_DEBUG + (("Completing parameter `%s' with type `%s'", + IDENTIFIER_POINTER (JDEP_MISC (dep)), + IDENTIFIER_POINTER (DECL_NAME (decl)))); + break; + + default: + fatal ("incomplete switch - java_complete_class"); + } + } + } + pop_obstacks (); + return; +} + +/* Resolve class CLASS_TYPE. Handle the case of trying to resolve an + array. */ + +static tree +resolve_class (class_type, decl, cl) + tree class_type, decl, cl; +{ + char *name = IDENTIFIER_POINTER (TYPE_NAME (class_type)); + char *base = name; + tree resolved_type, resolved_type_decl; + + /* 1- Check to see if we have an array. If true, find what we really + want to resolve */ + while (name[0] == '[') + name++; + if (base != name) + TYPE_NAME (class_type) = get_identifier (name); + + /* 2- Resolve the bare type */ + if (!(resolved_type_decl = do_resolve_class (class_type, decl, cl))) + return NULL_TREE; + resolved_type = TREE_TYPE (resolved_type_decl); + + /* 3- If we have and array, reconstruct the array down to its nesting */ + if (base != name) + { + while (base != name) + { + if (TREE_CODE (resolved_type) == RECORD_TYPE) + resolved_type = promote_type (resolved_type); + resolved_type = build_java_array_type (resolved_type, -1); + name--; + } + /* Build a fake decl for this, since this is what is expected to + be returned. */ + resolved_type_decl = + build_decl (TYPE_DECL, TYPE_NAME (resolved_type), resolved_type); + /* Figure how those two things are important for error report. FIXME */ + DECL_SOURCE_LINE (resolved_type_decl) = 0; + DECL_SOURCE_FILE (resolved_type_decl) = input_filename; + } + return resolved_type_decl; +} + +/* Effectively perform the resolution of class CLASS_TYPE. DECL or CL + are used to report error messages. */ + +static tree +do_resolve_class (class_type, decl, cl) + tree class_type; + tree decl; + tree cl; +{ + tree new_class_decl; + tree original_name = NULL_TREE; + + /* Do not try to replace TYPE_NAME (class_type) by a variable, since + its is changed by find_in_imports{_on_demand} */ + + /* 1- Check for the type in single imports */ + if (find_in_imports (class_type)) + return NULL_TREE; + + /* 2- And check for the type in the current compilation unit. If it fails, + try with a name qualified with the package name if appropriate. */ + + if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)))) + { + if (!CLASS_LOADED_P (TREE_TYPE (new_class_decl)) && + !CLASS_FROM_SOURCE_P (TREE_TYPE (new_class_decl))) + load_class (TYPE_NAME (class_type), 0); + return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)); + } + + original_name = TYPE_NAME (class_type); + if (!QUALIFIED_P (TYPE_NAME (class_type)) && ctxp->package) + TYPE_NAME (class_type) = merge_qualified_name (ctxp->package, + TYPE_NAME (class_type)); + if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)))) + { + if (!CLASS_LOADED_P (TREE_TYPE (new_class_decl)) && + !CLASS_FROM_SOURCE_P (TREE_TYPE (new_class_decl))) + load_class (TYPE_NAME (class_type), 0); + return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)); + } + TYPE_NAME (class_type) = original_name; + + /* 3- Check an other compilation unit that bears the name of type */ + load_class (TYPE_NAME (class_type), 0); + if (check_pkg_class_access (TYPE_NAME (class_type), + (cl ? cl : lookup_cl (decl)))) + return NULL_TREE; + + if ((new_class_decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)))) + return new_class_decl; + + /* 4- Check the import on demands. Don't allow bar.baz to be + imported from foo.* */ + if (!QUALIFIED_P (TYPE_NAME (class_type))) + if (find_in_imports_on_demand (class_type)) + return NULL_TREE; + + /* 5- Last call for a resolution */ + return IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)); +} + +/* Resolve NAME and lay it out (if not done and if not the current + parsed class). Return a decl node. */ + +static tree +resolve_and_layout (name, cl) + tree name; + tree cl; +{ + tree decl = resolve_no_layout (name, cl); + if (decl && TREE_TYPE (decl) != current_class + && !CLASS_LOADED_P (TREE_TYPE (decl))) + safe_layout_class (TREE_TYPE (decl)); + return decl; +} + +/* Resolve a class, returns its decl but doesn't perform any + layout. The current parsing context is saved and restored */ + +static tree +resolve_no_layout (name, cl) + tree name, cl; +{ + tree ptr, decl; + BUILD_PTR_FROM_NAME (ptr, name); + java_parser_context_save_global (); + decl = resolve_class (ptr, NULL_TREE, cl); + java_parser_context_restore_global (); + + return decl; +} + +/* Called to report errors. Skip leader '[' in a complex array type + description that failed to be resolved. */ + +static char * +purify_type_name (name) + char *name; +{ + while (*name && *name == '[') + name++; + return name; +} + +/* The type CURRENT refers to can't be found. We print error messages. */ + +static void +complete_class_report_errors (dep) + jdep *dep; +{ + switch (JDEP_KIND (dep)) + { + case JDEP_SUPER: + parse_error_context + (JDEP_WFL (dep), "Superclass `%s' of class `%s' not found", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); + break; + case JDEP_FIELD: + parse_error_context + (JDEP_WFL (dep), "Type `%s' not found in declaration of field `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); + break; + case JDEP_METHOD: /* Covers arguments */ + parse_error_context + (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " + "argument `%s' of method `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep))), + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_MISC (dep)))); + break; + case JDEP_METHOD_RETURN: /* Covers return type */ + parse_error_context + (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " + "return type of method `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_DECL_WFL (dep)))); + break; + case JDEP_INTERFACE: + parse_error_context + (JDEP_WFL (dep), "Superinterface `%s' of %s `%s' not found", + IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep))), + (CLASS_OR_INTERFACE (JDEP_DECL (dep), "class", "interface")), + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); + break; + case JDEP_VARIABLE: + parse_error_context + (JDEP_WFL (dep), "Type `%s' not found in the declaration of the " + "local variable `%s'", + purify_type_name (IDENTIFIER_POINTER (EXPR_WFL_NODE (JDEP_WFL (dep)))), + IDENTIFIER_POINTER (DECL_NAME (JDEP_DECL (dep)))); + break; + } +} + +/* Check uninitialized final. */ + +void +java_check_final () +{ +} + +static int +check_method_redefinition (class, method) + tree class, method; +{ + tree redef, name; + tree cl = DECL_NAME (method); + tree sig = TYPE_LANG_SPECIFIC (TREE_TYPE (method))->signature; + /* decl name of generated doesn't need to be fixed and + checked */ + if (DECL_NAME (method) != clinit_identifier_node) + { + /* NAME is just the plain name when Object is being defined */ + if (class != object_type_node) + name = DECL_NAME (method) = EXPR_WFL_NODE (DECL_NAME (method)); + else + name = DECL_NAME (method); + } + else + return 0; + + for (redef = TYPE_METHODS (class); redef; redef = TREE_CHAIN (redef)) + { + struct lang_type *t = TYPE_LANG_SPECIFIC (TREE_TYPE (redef)); + + if (! t || (redef == method)) + break; + if (DECL_NAME (redef) == name && sig == t->signature) + { + parse_error_context (cl, "Duplicate method declaration"); + return 1; + } + } + return 0; +} + +/* Check all the methods of CLASS. Methods are first completed then + checked according to regular method existance rules. + If no constructor were encountered, then build its declaration. */ + +static void +java_check_regular_methods (class_decl) + tree class_decl; +{ + tree method; + tree class = CLASS_TO_HANDLE_TYPE (TREE_TYPE (class_decl)); + tree super_class = CLASSTYPE_SUPER (class); + int seen_constructor = 0; + + TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); + + /* Should take interfaces into account. FIXME */ + for (method = TYPE_METHODS (class); method; method = TREE_CHAIN (method)) + { + tree found, sig; + tree method_wfl = DECL_NAME (method); + int aflags; + + if (DECL_CONSTRUCTOR_P (method)) + seen_constructor = 1; + + /* Check for redefinitions */ + if (check_method_redefinition (class, method)) + continue; + + sig = build_java_argument_signature (TREE_TYPE (method)); + + found = lookup_argument_method (super_class, DECL_NAME (method), sig); + if (! found) + continue; + /* Can't override a method with the same name and different return + types. */ + if (TREE_TYPE (TREE_TYPE (found)) != TREE_TYPE (TREE_TYPE (method))) + parse_warning_context + (method_wfl, + "Method `%s' redefined with different return type in class `%s'", + lang_printable_name (found), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + + /* Can't override final. Can't override static. */ + if (METHOD_FINAL (found) || METHOD_STATIC (found)) + { + /* Static *can* override static */ + if (METHOD_STATIC (found) && METHOD_STATIC (method)) + continue; + parse_error_context + (method_wfl, + "%s methods can't be overriden. Method `%s' is %s in class `%s'", + (METHOD_FINAL (found) ? "Final" : "Static"), + lang_printable_name (found), + (METHOD_FINAL (found) ? "final" : "static"), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + continue; + } + /* Static method can't override instance method. */ + if (METHOD_STATIC (method)) + { + parse_error_context + (method_wfl, + "Instance methods can't be overriden by a static method. Method " + "`%s' is an instance method in class `%s'", + lang_printable_name (found), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + continue; + } + /* Overriding/hiding public must be public or + overriding/hiding protected must be protected or public */ + if ((METHOD_PUBLIC (found) && !METHOD_PUBLIC (method)) || + (METHOD_PROTECTED (found) + && !(METHOD_PUBLIC (method) || METHOD_PROTECTED (method)))) + { + parse_error_context + (method_wfl, + "Methods can't be overridden to be more private. Method `%s' is " + "%s in class `%s'", lang_printable_name (found), + (METHOD_PUBLIC (found) ? "public" : "protected"), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + continue; + } + + /* If the method has default access in an other package, then + issue a warning that the current method doesn't override the one + that was found elsewhere */ + aflags = get_access_flags_from_decl (found); + if ((!aflags || (aflags > ACC_PROTECTED)) + && !class_in_current_package (DECL_CONTEXT (found))) + parse_warning_context + (method_wfl, "Method `%s' in class `%s' does not " + "override the corresponding method in class `%s', which is " + "private to a different package", + lang_printable_name (found), + IDENTIFIER_POINTER (DECL_NAME (class_decl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + + /* Check on (default) package access. FIXME. */ + /* Inheriting multiple methods with the same signature. FIXME */ + } + + TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); + + if (!seen_constructor) + { + /* No constructor seen, we craft one, at line 0 */ + int saved_lineno = lineno; + tree meth, decl; + lineno = 0; + meth = make_node (FUNCTION_TYPE); + TREE_TYPE (meth) = void_type_node; + TYPE_ARG_TYPES (meth) = NULL_TREE; + decl = add_method (class, 0, init_identifier_node, + build_java_signature (meth)); + DECL_CONSTRUCTOR_P (decl) = 1; + lineno = saved_lineno; + } +} + +/* Check abstract method of interface INTERFACE */ + +static void +java_check_abstract_methods (interface) + tree interface; +{ + int i, n; + tree method, basetype_vec, found; + + for (method = TYPE_METHODS (interface); method; method = TREE_CHAIN (method)) + { + char *csig; + tree name = DECL_NAME (method); + + /* 2- Check for double definition inside the defining interface */ + if (check_method_redefinition (interface, method)) + continue; + + /* 3- Overriding is OK as far as we preserve the return type and + the thrown exceptions */ + found = lookup_java_interface_method2 (interface, method); + if (found) + { + parse_error_context + (lookup_cl (method), + "Method `%s' previously defined in interface `%s' is " + "redefined with different return type in interface `%s'", + lang_printable_name (found), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found)))), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (interface)))); + continue; + } + } + + /* 4- Inherited methods can't differ by their returned types */ + if (!(basetype_vec = TYPE_BINFO_BASETYPES (interface))) + return; + n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; i < n; i++) + { + tree sub_interface_method, sub_interface; + tree vec_elt = TREE_VEC_ELT (basetype_vec, i); + if (!vec_elt) + continue; + sub_interface = BINFO_TYPE (vec_elt); + for (sub_interface_method = TYPE_METHODS (sub_interface); + sub_interface_method; + sub_interface_method = TREE_CHAIN (sub_interface_method)) + { + found = lookup_java_interface_method2 (interface, + sub_interface_method); + if (found && (found != sub_interface_method)) + parse_error_context + (lookup_cl (sub_interface_method), + "Interface `%s' inherits method `%s' from interface `%s'. This " + "method is redefined with a different return " + "type in interface `%s'", + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (interface))), + lang_printable_name (found), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (sub_interface_method)))), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + } + } +} + +/* Check the method on all the defined classes. Should be done to the + classes declared in the compilation unit only. FIXME */ + +void +java_check_methods () +{ + + tree current; + for (current = ctxp->class_list; current; current = TREE_CHAIN (current)) + if (CLASS_FROM_SOURCE_P (TREE_TYPE (current))) + { + tree class = CLASS_TO_HANDLE_TYPE (TREE_TYPE (current)); + + if (CLASS_INTERFACE (TYPE_NAME (class))) + java_check_abstract_methods (class); + else + java_check_regular_methods (current); + } +} + +/* Lookup methods in interfaces using their name and partial + signature. Return a matching method only if their types differ. */ + +static tree +lookup_java_interface_method2 (class, method_decl) + tree class, method_decl; +{ + int i, n; + tree basetype_vec = TYPE_BINFO_BASETYPES (class), to_return; + + if (!basetype_vec) + return NULL_TREE; + + n = TREE_VEC_LENGTH (basetype_vec); + for (i = 0; i < n; i++) + { + tree vec_elt = TREE_VEC_ELT (basetype_vec, i), to_return; + if ((BINFO_TYPE (vec_elt) != object_type_node) + && (to_return = + lookup_java_method2 (BINFO_TYPE (vec_elt), method_decl, 1))) + return to_return; + } + for (i = 0; i < n; i++) + { + to_return = lookup_java_interface_method2 + (BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i)), method_decl); + if (to_return) + return to_return; + } + + return NULL_TREE; +} + +/* Lookup method using their name and partial signature. Return a + matching method only if their types differ. */ + +static tree +lookup_java_method2 (clas, method_decl, do_interface) + tree clas, method_decl; + int do_interface; +{ + tree method, method_signature, method_name, method_type; + method_signature = build_java_argument_signature (TREE_TYPE (method_decl)); + method_name = DECL_NAME (method_decl); + method_type = TREE_TYPE (TREE_TYPE (method_decl)); + + while (clas != NULL_TREE) + { + for (method = TYPE_METHODS (clas); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree method_sig = build_java_argument_signature (TREE_TYPE (method)); + if (DECL_NAME (method) == method_name + && method_sig == method_signature + && TREE_TYPE (TREE_TYPE (method)) != method_type) + { + return method; + } + } + clas = (do_interface ? NULL_TREE : CLASSTYPE_SUPER (clas)); + } + return NULL_TREE; +} + +/* Return the line that matches DECL line number. Used during error + report */ + +static tree +lookup_cl (decl) + tree decl; +{ + static tree cl = NULL_TREE; + + if (!decl) + return NULL_TREE; + + if (cl == NULL_TREE) + cl = build_expr_wfl (NULL_TREE, NULL, 0, 0); + + EXPR_WFL_FILENAME_NODE (cl) = get_identifier (DECL_SOURCE_FILE (decl)); + EXPR_WFL_SET_LINECOL (cl, DECL_SOURCE_LINE_FIRST (decl), -1); + + return cl; +} + +/* Look for a simple name in the single-type import list */ + +static tree +find_name_in_single_imports (name) + tree name; +{ + tree node; + + for (node = ctxp->import_list; node; node = TREE_CHAIN (node)) + if (TREE_VALUE (node) == name) + return (EXPR_WFL_NODE (TREE_PURPOSE (node))); + + return NULL_TREE; +} + +/* Process all single-type import. */ + +static int +process_imports () +{ + tree import; + int error_found; + + for (import = ctxp->import_list; import; import = TREE_CHAIN (import)) + { + tree to_be_found = EXPR_WFL_NODE (TREE_PURPOSE (import)); + + /* Don't load twice something already defined. */ + if (IDENTIFIER_CLASS_VALUE (to_be_found)) + continue; + QUALIFIED_P (to_be_found) = 1; + load_class (to_be_found, 0); + error_found = + check_pkg_class_access (to_be_found, TREE_PURPOSE (import)); + if (!IDENTIFIER_CLASS_VALUE (to_be_found)) + { + parse_error_context (TREE_PURPOSE (import), + "Class or interface `%s' not found in import", + IDENTIFIER_POINTER (to_be_found)); + return 1; + } + if (error_found) + return 1; + } + return 0; +} + +/* Possibly find a class imported by a single-type import statement. Return + 1 if an error occured, 0 otherwise. */ + +static int +find_in_imports (class_type) + tree class_type; +{ + tree import; + + for (import = ctxp->import_list; import; import = TREE_CHAIN (import)) + if (TREE_VALUE (import) == TYPE_NAME (class_type)) + { + TYPE_NAME (class_type) = EXPR_WFL_NODE (TREE_PURPOSE (import)); + QUALIFIED_P (TYPE_NAME (class_type)) = 1; + return check_pkg_class_access (TYPE_NAME (class_type), + TREE_PURPOSE (import)); + } + return 0; +} + +/* Process a import on demand statement (lazy) */ + +static int +read_import_entry (jcf, dirp, returned_name) + JCF *jcf; + DIR *dirp; + char **returned_name; +{ + if (dirp) + { + struct dirent *direntp = readdir (dirp); + if (!direntp) + { + *returned_name = NULL; + return 0; + } + else + { + *returned_name = direntp->d_name; + return (strlen (direntp->d_name)); + } + } + else + { + int current_dir_len = strlen (jcf->classname); + char *current_entry; + int current_entry_len; + + /* Here we read a zip directory as a file directory. The files + we're selecting must have the same root than the directory + we're examining. */ + + ZipDirectory *zipd = (ZipDirectory *)jcf->zipd; + + while (zipd) + { + current_entry = ZIPDIR_FILENAME (zipd); + current_entry_len = zipd->filename_length; + while (current_entry_len && current_entry [current_entry_len] != '/') + current_entry_len--; + /* If the path of the current file doesn't match the directory we're + scanning, that the end of the search */ + current_entry_len++; + if (strncmp (jcf->classname, current_entry, current_dir_len)) + { + *returned_name = NULL; + return 0; + } + /* Ok, we have at least the same path. The position of the last '/' + of the current file we're examining should match the size of + name of the directory we're browsing, otherwise that an entry + belonging to a sub directory, we want to skip it. */ + if (current_entry_len != current_dir_len) + zipd = ZIPDIR_NEXT (zipd); + else + { + jcf->zipd = ZIPDIR_NEXT (zipd); /* Prepare next read */ + *returned_name = ¤t_entry [current_entry_len]; + return (zipd->filename_length - current_entry_len); + } + } + } +} + +/* Read a import directory, gathering potential match for further type + references. Indifferently reads a filesystem or a ZIP archive + directory. */ + +static void +read_import_dir (wfl) + tree wfl; +{ + char *name = IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl)); + int name_len = IDENTIFIER_LENGTH (EXPR_WFL_NODE (wfl)), reclen; + DIR *dirp = NULL; + tree dirname = ident_subst (name, name_len, "", '.', '/', ""); + JCF jcfr, *jcf, *saved_jcf = current_jcf; + char *founddirname, *d_name; + struct ZipFileCache zip_cache; + + jcf = &jcfr; + if (!classpath) + fix_classpath (); + if (!(founddirname = find_class (name, name_len, jcf, 0))) + fatal ("Can't import `%s'", name); + if (jcf->outofsynch) + jcf_out_of_synch (jcf); + if (jcf->seen_in_zip) + jcf->zipd = ZIPDIR_NEXT ((ZipDirectory *)jcf->zipd); + + else if (founddirname && (dirp = opendir (founddirname))) + { + readdir (dirp); readdir (dirp); + } + + if (!founddirname && !dirp) + { + static int first = 1; + if (first) + { + char buffer [256]; + sprintf (buffer, "Can't find default package `%s'. Check " + "the CLASSPATH environment variable and the access to the " + "archives.", name); + error (buffer); + java_error_count++; + first = 0; + } + else + parse_error_context (wfl, "Package `%s' not found in import", name); + current_jcf = saved_jcf; + return; + } + + /* Here we should have a unified way of retrieving an entry, to be + indexed. */ + while ((reclen = read_import_entry (jcf, dirp, &d_name))) + { + int java_or_class = 0; + int len; + if ((reclen > 5) + && !strcmp (&d_name [reclen-5], ".java")) + { + java_or_class = 1; + len = reclen - 5; + } + + if (!java_or_class && (reclen > 6) && + !strcmp (&d_name [reclen-6], ".class")) + { + java_or_class = 2; + len = reclen - 6; + } + + if (java_or_class) + { + char *id_name; + tree node, old; + + obstack_grow (&temporary_obstack, name, name_len); + obstack_1grow (&temporary_obstack, '/'); + obstack_grow0 (&temporary_obstack, d_name, len); + id_name = obstack_finish (&temporary_obstack); + + node = get_identifier (id_name); + IS_A_CLASSFILE_NAME (node) = 1; /* Or soon to be */ + QUALIFIED_P (node) = 1; /* As soon as we turn / into . */ + } + } + if (dirp) + closedir (dirp); + + current_jcf = saved_jcf; +} + +/* Possibly find a type in the import on demands specified + types. Returns 1 if an error occured, 0 otherwise. Run throught the + entire list, to detected potential double definitions. */ + +static int +find_in_imports_on_demand (class_type) + tree class_type; +{ + tree node, import, node_to_use; + int seen_once = -1; + tree cl; + + for (import = ctxp->import_demand_list; import; import = TREE_CHAIN (import)) + { + char *id_name; + tree found; + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (EXPR_WFL_NODE (TREE_PURPOSE (import))), + IDENTIFIER_LENGTH (EXPR_WFL_NODE (TREE_PURPOSE (import)))); + obstack_1grow (&temporary_obstack, '/'); + obstack_grow0 (&temporary_obstack, + IDENTIFIER_POINTER (TYPE_NAME (class_type)), + IDENTIFIER_LENGTH (TYPE_NAME (class_type))); + id_name = obstack_finish (&temporary_obstack); + + node = maybe_get_identifier (id_name); + if (node && IS_A_CLASSFILE_NAME (node)) + { + if (seen_once < 0) + { + cl = TREE_PURPOSE (import); + seen_once = 1; + node_to_use = node; + } + else + { + seen_once++; + parse_error_context + (import, "Type `%s' also potentially defined in package `%s'", + IDENTIFIER_POINTER (TYPE_NAME (class_type)), + IDENTIFIER_POINTER (EXPR_WFL_NODE (TREE_PURPOSE (import)))); + } + } + } + + if (seen_once == 1) + { + /* Setup lineno so that it refers to the line of the import (in + case we parse a class file and encounter errors */ + tree decl; + int saved_lineno = lineno; + lineno = EXPR_WFL_LINENO (cl); + TYPE_NAME (class_type) = ident_subst (IDENTIFIER_POINTER (node_to_use), + IDENTIFIER_LENGTH (node_to_use), + "", '/', '.', ""); + QUALIFIED_P (TYPE_NAME (class_type)) = 1; + decl = IDENTIFIER_CLASS_VALUE (TYPE_NAME (class_type)); + /* If there is no DECL set for the class or if the class isn't + loaded and not seen in source yet, the load */ + if (!decl || (!CLASS_LOADED_P (TREE_TYPE (decl)) + && !CLASS_FROM_SOURCE_P (TREE_TYPE (decl)))) + load_class (node_to_use, 0); + lineno = saved_lineno; + return check_pkg_class_access (TYPE_NAME (class_type), cl); + } + else + return (seen_once < 0 ? 0 : seen_once); /* It's ok not to have found */ +} + +/* Check that CLASS_NAME refers to a PUBLIC class. Return 0 if no + access violations were found, 1 otherwise. */ + +static int +check_pkg_class_access (class_name, cl) + tree class_name; + tree cl; +{ + tree type; + int access; + + if (!QUALIFIED_P (class_name) || !IDENTIFIER_CLASS_VALUE (class_name)) + return 0; + + if (!(type = TREE_TYPE (IDENTIFIER_CLASS_VALUE (class_name)))) + return 0; + + if (!CLASS_PUBLIC (TYPE_NAME (type))) + { + parse_error_context + (cl, "Can't access %s `%s'. Only public classes and interfaces in " + "other packages can be accessed", + (CLASS_INTERFACE (TYPE_NAME (type)) ? "interface" : "class"), + IDENTIFIER_POINTER (class_name)); + return 1; + } + return 0; +} + +/* Local variable declaration. */ + +static void +declare_local_variables (modifier, type, vlist) + int modifier; + tree type; + tree vlist; +{ + tree decl, current, returned_type, type_wfl, init_stmt = NULL_TREE; + int must_chain = 0; + + /* Push a new block if statement were seen between the last time we + pushed a block and now. Keep a cound of block to close */ + if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (current_function_decl))) + { + tree body = DECL_FUNCTION_BODY (current_function_decl); + tree b = enter_block (); + BLOCK_EXPR_ORIGIN(b) = body; + } + + if (modifier) + { + int i; + for (i = 0; i <= 10; i++) if (1 << i & modifier) break; + parse_error_context + (ctxp->modifier_ctx [i], + (modifier == ACC_FINAL ? + "Unsupported JDK1.1 `final' locals" : + "Only `final' is allowed as a local variables modifier")); + return; + } + + if (unresolved_type_p (type, &returned_type)) + { + if (returned_type) + type = returned_type; + else + { + type_wfl = type; + type = obtain_incomplete_type (type); + must_chain = 1; + } + } + + for (current = vlist; current; current = TREE_CHAIN (current)) + { + tree wfl = TREE_PURPOSE (current); + tree name = EXPR_WFL_NODE (wfl); + tree init = TREE_VALUE (current); + tree other = lookup_name_in_blocks (name); + + /* Don't try to use an INIT statement when an error was found */ + if (init && java_error_count) + init = NULL_TREE; + + if (other) + parse_error_context + (wfl, "Variable `%s' is already defined in this method and was " + "declared `%s %s' in line %d", + IDENTIFIER_POINTER (name), lang_printable_name (TREE_TYPE (other)), + IDENTIFIER_POINTER (name), DECL_SOURCE_LINE (other)); + else + { + if (!must_chain && TREE_CODE (type) == RECORD_TYPE) + type = promote_type (type); + /* Never layout this decl. This will be done when its scope + will be entered */ + decl = build_decl_no_layout (VAR_DECL, name, type); + BLOCK_CHAIN_DECL (decl); + + /* Add the initialization function to the current function's code */ + if (init) + { + tree wfl; + MODIFY_EXPR_FROM_INITIALIZATION_P (init) = 1; + java_method_add_stmt + (current_function_decl, + build_debugable_stmt (EXPR_WFL_LINECOL (init), init)); + } + + if (must_chain) + { + jdep *dep; + register_incomplete_type (JDEP_VARIABLE, type_wfl, decl, type); + dep = CLASSD_LAST (ctxp->classd_list); + JDEP_GET_PATCH (dep) = &TREE_TYPE (decl); + } + } + } + SOURCE_FRONTEND_DEBUG (("Defined locals")); +} + +/* Called during parsing. Build decls from argument list. */ + +static void +source_start_java_method (fndecl) + tree fndecl; +{ + tree tem; + tree parm_decl; + int i; + + extern tree current_binding_level; + current_function_decl = fndecl; + + /* New scope for the function */ + enter_block (); + for (tem = TYPE_ARG_TYPES (TREE_TYPE (fndecl)), i = 0; + tem != NULL_TREE; tem = TREE_CHAIN (tem), i++) + { + tree type = TREE_VALUE (tem); + tree name = TREE_PURPOSE (tem); + + /* If type is incomplete. Layout can't take place + now. Create an incomplete decl and ask for the decl to be + patched later */ + if (INCOMPLETE_TYPE_P (type)) + { + jdep *jdep; + parm_decl = build_decl_no_layout (PARM_DECL, name, type); + + register_incomplete_type (JDEP_PARM, NULL_TREE, NULL_TREE, type); + jdep = CLASSD_LAST (ctxp->classd_list); + JDEP_MISC (jdep) = name; + JDEP_GET_PATCH (jdep) = &TREE_TYPE (parm_decl); + } + else + parm_decl = build_decl (PARM_DECL, name, type); + + BLOCK_CHAIN_DECL (parm_decl); + } + tem = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)); + BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)) = + nreverse (tem); + DECL_ARG_SLOT_COUNT (current_function_decl) = i; +} + +/* Called during expansion. Push decls formerly built from argument + list so they're usable during expansion. */ + +static void +expand_start_java_method (fndecl) + tree fndecl; +{ + tree tem, *ptr; + tree parm_decl; + + extern tree current_binding_level; + current_function_decl = fndecl; + + announce_function (fndecl); + pushlevel (1); /* Push parameters */ + ptr = &DECL_ARGUMENTS (fndecl); + tem = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (current_function_decl)); + while (tem) + { + tree next = TREE_CHAIN (tem); + DECL_ARG_TYPE (tem) = TREE_TYPE (tem); + layout_decl (tem, 0); + pushdecl (tem); + INITIALIZED_P (tem) = 1; /* Parms are initialized */ + *ptr = tem; + ptr = &TREE_CHAIN (tem); + tem = next; + } + *ptr = NULL_TREE; + pushdecl_force_head (DECL_ARGUMENTS (fndecl)); + lineno = DECL_SOURCE_LINE_FIRST (fndecl); + complete_start_java_method (fndecl); +} + +/* Terminate a function and expand its body. */ + +static void +source_end_java_method () +{ + tree fndecl = current_function_decl; + + java_parser_context_save_global (); + lineno = ctxp->last_ccb_indent1; + + /* Generate function's code */ + if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) + && ! flag_emit_class_files) + expand_expr_stmt (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl))); + + /* pop out of its parameters */ + pushdecl_force_head (DECL_ARGUMENTS (fndecl)); + poplevel (1, 0, 1); + BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl; + + /* Generate rtl for function exit. */ + if (! flag_emit_class_files) + { + lineno = DECL_SOURCE_LINE_LAST (fndecl); + expand_function_end (input_filename, lineno, 0); + + /* Run the optimizers and output assembler code for this function. */ + rest_of_compilation (fndecl); + } + + current_function_decl = NULL_TREE; + /* permanent_allocation (1); */ + java_parser_context_restore_global (); +} + +/* Record EXPR in the current function block. Complements compound + expression second operand if necessary. */ + +tree +java_method_add_stmt (fndecl, expr) + tree fndecl, expr; +{ + tree body = BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)); + tree node; + + if (java_error_count) + return body; + if ((node = add_stmt_to_compound (body, NULL_TREE, expr)) == body) + return body; + + BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (fndecl)) = node; + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* Add STMT to EXISTING if possible, otherwise create a new + COMPOUND_EXPR and add STMT to it. */ + +static tree +add_stmt_to_compound (existing, type, stmt) + tree existing, type, stmt; +{ + tree node; + + if (existing && (TREE_CODE (existing) == COMPOUND_EXPR) + && TREE_OPERAND (existing, 1) == size_zero_node) + { + TREE_OPERAND (existing, 1) = stmt; + TREE_TYPE (existing) = type; + return existing; + } + else if (existing) + node = build (COMPOUND_EXPR, type, existing, stmt); + else + node = build (COMPOUND_EXPR, type, stmt, size_zero_node); + + return node; +} + +/* Hold THIS for the scope of the current public method decl. */ +static tree current_this; + +/* Layout all class found during parsing */ + +void +java_layout_classes () +{ + tree current; + for (current = ctxp->class_list; current; current = TREE_CHAIN (current)) + { + current_class = TREE_TYPE (current); + TYPE_FIELDS (current_class) = nreverse (TYPE_FIELDS (current_class)); + if (!TYPE_SIZE (current_class)) + safe_layout_class (current_class); + } +} + +/* Expand all methods in all registered classes. */ + +void +java_complete_expand_methods () +{ + tree current; + + for (current = ctxp->class_list; current; current = TREE_CHAIN (current)) + { + extern tree current_constant_pool_data_ref; + tree class_type = CLASS_TO_HANDLE_TYPE (TREE_TYPE (current)); + tree decl; + int saved_lineno; + + current_class = TREE_TYPE (current); + + /* Initialize a new constant pool */ + init_outgoing_cpool (); + + /* Don't process function bodies in interfaces */ + if (!CLASS_INTERFACE (TYPE_NAME (current_class))) + for (decl = TYPE_METHODS (class_type); decl; decl = TREE_CHAIN (decl)) + { + current_function_decl = decl; + /* Don't generate debug info on line zero when expanding a + generated constructor. */ + if (DECL_CONSTRUCTOR_P (decl) && !DECL_FUNCTION_BODY (decl)) + { + /* If we found errors, it's too dangerous to try to generate + and expand a constructor */ + if (!java_error_count) + { + restore_line_number_status (1); + java_complete_expand_method (decl); + restore_line_number_status (0); + } + } + else + java_complete_expand_method (decl); + } + + /* Make the class data, register it and run the rest of decl + compilation on it */ + if (!java_error_count && ! flag_emit_class_files) + { + make_class_data (current_class); + register_class (); + rest_of_decl_compilation (TYPE_NAME (current_class), (char*) 0, 1, 0); + } + } +} + +/* Complete and expand a method. */ + +static void +java_complete_expand_method (mdecl) + tree mdecl; +{ + tree node; + jdep *current; + int no_ac_found = 1; + + /* We generate some code for an empty constructor */ + if (DECL_CONSTRUCTOR_P (mdecl) && !DECL_FUNCTION_BODY (mdecl)) + { + tree arg_list, func, call; + tree method_type = TREE_TYPE (mdecl); + tree class_type = CLASS_TO_HANDLE_TYPE (current_class); + tree self_type = (CLASSTYPE_SUPER (class_type) ? + CLASSTYPE_SUPER (class_type) : class_type); + tree method_signature = + TYPE_LANG_SPECIFIC (method_type)->signature; + tree method = + lookup_java_constructor (CLASS_TO_HANDLE_TYPE (self_type), + method_signature); + tree block, compound; + + /* Fixe the begining/ending lines of the method so that with + no_line_numbers set to 1 it doesn't generate debug info at + line 1 for this artificial constructor. */ + DECL_SOURCE_LINE (mdecl) = 1; + DECL_SOURCE_LINE_MERGE (mdecl, 1); + source_start_java_method (mdecl); + arg_list = BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)); + enter_block (); + func = build_known_method_ref (method, method_type, self_type, + method_signature, arg_list); + + if (! flag_emit_class_files) + func = build1 (NOP_EXPR, build_pointer_type (method_type), func); + call = build (CALL_EXPR, TREE_TYPE (method_type), func, + build_tree_list (NULL_TREE, arg_list), NULL_TREE); + TREE_SIDE_EFFECTS (call) = 1; + call = build_class_init (self_type, call); + compound = java_method_add_stmt (mdecl, call); + block = exit_block (); + BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) = block; + /* The function decl, its block and the compound statement + within this block are all of void type. */ + TREE_TYPE (block) = TREE_TYPE (compound) = + TREE_TYPE (DECL_FUNCTION_BODY (mdecl)) = void_type_node; + exit_block (); + no_ac_found = 0; + } + + if (DECL_FUNCTION_BODY (mdecl)) + { + expand_start_java_method (mdecl); + + current_this + = (!METHOD_STATIC (mdecl) ? + BLOCK_EXPR_DECLS (DECL_FUNCTION_BODY (mdecl)) : NULL_TREE); + + if (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl)) && no_ac_found) + java_complete_tree (BLOCK_EXPR_BODY (DECL_FUNCTION_BODY (mdecl))); + /* Don't go any further if we've found error(s) during the + expansion */ + if (!java_error_count) + source_end_java_method (); + } +} + +/* Expand finals. */ + +void +java_expand_finals () +{ +} + +/* Wrap non WFL PRIMARY around a WFL and set EXPR_WFL_QUALIFICATION to + a tree list node containing RIGHT. Fore coming RIGHTs will be + chained to this hook. LOCATION contains the location of the + separating `.' operator. */ + +static tree +make_qualified_primary (primary, right, location) + tree primary, right; + int location; +{ + tree wfl; + + /* We want to process THIS . xxx symbolicaly, to keep it consistent + with the way we're processing SUPER. A THIS from a primary as a + different form than a SUPER. Turn THIS into something symbolic */ + if (TREE_CODE (primary) == JAVA_THIS_EXPR) + { + wfl = build_wfl_node (this_identifier_node, input_filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (primary); + wfl = make_qualified_name (wfl, right, location); + PRIMARY_P (wfl) = 1; + return wfl; + } + /* Other non WFL node are wrapped around a WFL */ + else if (TREE_CODE (primary) != EXPR_WITH_FILE_LOCATION) + { + wfl = build_expr_wfl (NULL_TREE, ctxp->filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (primary); + EXPR_WFL_QUALIFICATION (wfl) = build_tree_list (primary, NULL_TREE); + } + else + { + wfl = primary; + if (!EXPR_WFL_QUALIFICATION (primary)) + EXPR_WFL_QUALIFICATION (primary) = + build_tree_list (primary, NULL_TREE); + } + + EXPR_WFL_LINECOL (right) = location; + chainon (EXPR_WFL_QUALIFICATION (wfl), build_tree_list (right, NULL_TREE)); + PRIMARY_P (wfl) = 1; + return wfl; +} + +/* Simple merge of two name separated by a `.' */ + +static tree +merge_qualified_name (left, right) + tree left, right; +{ + tree node; + obstack_grow (&temporary_obstack, IDENTIFIER_POINTER (left), + IDENTIFIER_LENGTH (left)); + obstack_1grow (&temporary_obstack, '.'); + obstack_grow0 (&temporary_obstack, IDENTIFIER_POINTER (right), + IDENTIFIER_LENGTH (right)); + node = get_identifier (obstack_base (&temporary_obstack)); + obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); + QUALIFIED_P (node) = 1; + return node; +} + +/* Merge the two parts of a qualified name into LEFT. Set the + location information of the resulting node to LOCATION, usually + inherited from the location information of the `.' operator. */ + +static tree +make_qualified_name (left, right, location) + tree left, right; + int location; +{ + int qualified; + tree left_id = EXPR_WFL_NODE (left); + tree right_id = EXPR_WFL_NODE (right); + tree wfl, merge; + + merge = merge_qualified_name (left_id, right_id); + + /* Left wasn't qualified and is now qualified */ + if (!QUALIFIED_P (left_id)) + { + tree wfl = build_expr_wfl (left_id, ctxp->filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = EXPR_WFL_LINECOL (left); + EXPR_WFL_QUALIFICATION (left) = build_tree_list (wfl, NULL_TREE); + } + + wfl = build_expr_wfl (right_id, ctxp->filename, 0, 0); + EXPR_WFL_LINECOL (wfl) = location; + chainon (EXPR_WFL_QUALIFICATION (left), build_tree_list (wfl, NULL_TREE)); + + EXPR_WFL_NODE (left) = merge; + return left; +} + +/* Extract the last identifier component of the qualified in WFL. The + last identifier is removed from the linked list */ + +static tree +cut_identifier_in_qualified (wfl) + tree wfl; +{ + tree q; + tree previous = NULL_TREE; + for (q = EXPR_WFL_QUALIFICATION (wfl); ; previous = q, q = TREE_CHAIN (q)) + if (!TREE_CHAIN (q)) + { + if (!previous) + fatal ("Operating on a non qualified qualified WFL - " + "cut_identifier_in_qualified"); + TREE_CHAIN (previous) = NULL_TREE; + return TREE_PURPOSE (q); + } +} + +/* Resolve the expression name NAME. Return its decl. */ + +static tree +resolve_expression_name (id) + tree id; +{ + tree name = EXPR_WFL_NODE (id); + tree decl; + + /* 6.5.5.1: Simple expression names */ + if (!PRIMARY_P (id) && !QUALIFIED_P (name)) + { + /* 15.13.1: NAME can appear within the scope of a local variable + declaration */ + if ((decl = IDENTIFIER_LOCAL_VALUE (name))) + return decl; + + /* 15.13.1: NAME can appear within a class declaration */ + else + { + decl = lookup_field_wrapper (current_class, name); + if (decl) + { + int fs = FIELD_STATIC (decl); + /* Instance variable (8.3.1.1) can't appear within + static method, static initializer or initializer for + a static variable. */ + if (!fs && METHOD_STATIC (current_function_decl)) + { + parse_error_context + (id, "Can't make a static reference to nonstatic variable " + "`%s' in class `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (DECL_NAME + (TYPE_NAME (current_class)))); + return error_mark_node; + } + decl = build_field_ref ((fs ? NULL_TREE : current_this), + current_class, name); + return (fs ? build_class_init (current_class, decl) : decl); + } + /* Fall down to error report on undefined variable */ + } + } + /* 6.5.5.2 Qualified Expression Names */ + else + { + qualify_ambiguous_name (id); + /* 15.10.1 Field Access Using a Primary and/or Expression Name */ + /* 15.10.2: Accessing Superclass Members using super */ + return resolve_field_access (id, NULL, NULL); + } + + /* We've got an error here */ + parse_error_context (id, "Undefined variable `%s'", + IDENTIFIER_POINTER (name)); + + return error_mark_node; +} + +/* 15.10.1 Field Acess Using a Primary and/or Expression Name. + We return something suitable to generate the field access. We also + return the field decl in FIELD_DECL and its type in FIELD_TYPE. If + recipient's address can be null. */ + +static tree +resolve_field_access (qual_wfl, field_decl, field_type) + tree qual_wfl; + tree *field_decl, *field_type; +{ + int is_static = 0; + tree field_ref; + tree decl, where_found, type_found; + + if (resolve_qualified_expression_name (qual_wfl, &decl, + &where_found, &type_found)) + return error_mark_node; + + /* Resolve the LENGTH field of an array here */ + if (DECL_NAME (decl) == length_identifier_node && TYPE_ARRAY_P (type_found) + && ! flag_emit_class_files) + { + tree length = build_java_array_length_access (where_found); + field_ref = + build_java_arraynull_check (type_found, length, int_type_node); + } + /* We might have been trying to resolve field.method(). In which + case, the resolution is over and decl is the answer */ + else if (DECL_P (decl) && IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl)) == decl) + field_ref = decl; + else if (DECL_P (decl)) + { + is_static = DECL_P (decl) && FIELD_STATIC (decl); + field_ref = build_field_ref ((is_static ? NULL_TREE : where_found), + type_found, DECL_NAME (decl)); + if (field_ref == error_mark_node) + return error_mark_node; + if (is_static) + { + field_ref = build_class_init (type_found, field_ref); + /* If the static field was identified by an expression that + needs to be generated, make the field access a compound + expression whose first part of the evaluation of the + field selector part. */ + if (where_found && TREE_CODE (where_found) != TYPE_DECL) + { + tree type = QUAL_DECL_TYPE (field_ref); + field_ref = build (COMPOUND_EXPR, type, where_found, field_ref); + } + } + } + else + field_ref = decl; + + if (field_decl) + *field_decl = decl; + if (field_type) + *field_type = QUAL_DECL_TYPE (decl); + return field_ref; +} + +/* 6.5.5.2: Qualified Expression Names */ + +static int +resolve_qualified_expression_name (wfl, found_decl, where_found, type_found) + tree wfl; + tree *found_decl, *type_found, *where_found; +{ + int from_type = 0; /* Field search initiated from a type */ + int from_super = 0, from_cast = 0; + int previous_call_static = 0; + int is_static; + tree decl = NULL_TREE, type = NULL_TREE, q; + *where_found = NULL_TREE; + + for (q = EXPR_WFL_QUALIFICATION (wfl); q; q = TREE_CHAIN (q)) + { + tree qual_wfl = QUAL_WFL (q); + + /* 15.10.1 Field Access Using a Primary */ + + switch (TREE_CODE (qual_wfl)) + { + case CALL_EXPR: + case JAVA_NEW_CLASS_EXPR: + /* If the access to the function call is a non static field, + build the code to access it. */ + if (DECL_P (decl) && !FIELD_STATIC (decl)) + { + decl = maybe_access_field (decl, *where_found, type); + if (decl == error_mark_node) + return 1; + } + /* And code for the function call */ + if (complete_function_arguments (qual_wfl)) + return 1; + *where_found = + patch_method_invocation_stmt (qual_wfl, decl, type, &is_static); + if (*where_found == error_mark_node) + return 1; + *type_found = type = QUAL_DECL_TYPE (*where_found); + + /* If the previous call was static and this one is too, + build a compound expression to hold the two (because in + that case, previous function calls aren't transported as + forcoming function's argument. */ + if (previous_call_static && is_static) + { + decl = build (COMPOUND_EXPR, type, decl, *where_found); + TREE_SIDE_EFFECTS (decl) = 1; + } + else + { + previous_call_static = is_static; + decl = *where_found; + } + continue; + + case CONVERT_EXPR: + *where_found = decl = java_complete_tree (qual_wfl); + if (decl == error_mark_node) + return 1; + *type_found = type = QUAL_DECL_TYPE (decl); + from_cast = 1; + continue; + + case ARRAY_REF: + /* If the access to the function call is a non static field, + build the code to access it. */ + if (DECL_P (decl) && !FIELD_STATIC (decl)) + { + decl = maybe_access_field (decl, *where_found, type); + if (decl == error_mark_node) + return 1; + } + /* And code for the array reference expression */ + decl = java_complete_tree (qual_wfl); + if (decl == error_mark_node) + return 1; + type = QUAL_DECL_TYPE (decl); + continue; + } + + /* If we fall here, we weren't processing a (static) function call. */ + previous_call_static = 0; + + /* It can be the keyword THIS */ + if (EXPR_WFL_NODE (qual_wfl) == this_identifier_node) + { + if (!current_this) + { + parse_error_context + (wfl, "Keyword `this' used outside allowed context"); + return 1; + } + /* We have to generate code for intermediate acess */ + *where_found = decl = current_this; + type = QUAL_DECL_TYPE (decl); + continue; + } + + /* 15.10.2 Accessing Superclass Members using SUPER */ + if (EXPR_WFL_NODE (qual_wfl) == super_identifier_node) + { + tree node; + /* Check on the restricted use of SUPER */ + if (METHOD_STATIC (current_function_decl) + || current_class == object_type_node) + { + parse_error_context + (wfl, "Keyword `super' used outside allowed context"); + return 1; + } + /* Otherwise, treat SUPER as (SUPER_CLASS)THIS */ + node = build_cast (EXPR_WFL_LINECOL (qual_wfl), + CLASSTYPE_SUPER (current_class), + build_this (EXPR_WFL_LINECOL (qual_wfl))); + *where_found = decl = java_complete_tree (node); + *type_found = type = QUAL_DECL_TYPE (decl); + from_super = from_type = 1; + continue; + } + + /* 15.13.1: Can't search for field name in packages, so we + assume a variable/class name was meant. */ + if (RESOLVE_PACKAGE_NAME_P (qual_wfl)) + { + if (from_super || from_cast) + parse_error_context + ((from_cast ? qual_wfl : wfl), + "No variable `%s' defined in class `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)), + lang_printable_name (type)); + else + parse_error_context + (qual_wfl, "Undefined variable or class name: `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl))); + return 1; + } + + /* We have a type name. It's been already resolved when the + expression was qualified. */ + else if (RESOLVE_TYPE_NAME_P (qual_wfl)) + { + if (!(decl = QUAL_RESOLUTION (q))) + return 1; /* Error reported already */ + + if (not_accessible_p (TREE_TYPE (decl), decl, 0)) + { + parse_error_context + (qual_wfl, "Can't access %s field `%s.%s' from `%s'", + java_accstring_lookup (get_access_flags_from_decl (decl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), + IDENTIFIER_POINTER (DECL_NAME (decl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)))); + return 1; + } + + type = TREE_TYPE (decl); + from_type = 1; + } + /* We resolve and expression name */ + else + { + tree field_decl; + + /* If there exists an early resolution, use it. That occurs + only once and we know that there are more things to + come. Don't do that when processing something after SUPER + (we need more thing to be put in place below */ + if (!from_super && QUAL_RESOLUTION (q)) + decl = QUAL_RESOLUTION (q); + + /* We have to search for a field, knowing the type of its + container. The flag FROM_TYPE indicates that we resolved + the last member of the expression as a type name, which + means that for the resolution of this field, will check + on other errors than if the it was resolved as a member + of an other field. */ + else + { + int is_static; + if (!from_type && !JREFERENCE_TYPE_P (type)) + { + parse_error_context + (qual_wfl, "Attempt to reference field `%s' in `%s %s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)), + lang_printable_name (type), + IDENTIFIER_POINTER (DECL_NAME (field_decl))); + return 1; + } + + if (!(field_decl = + lookup_field_wrapper (type, EXPR_WFL_NODE (qual_wfl)))) + { + parse_error_context + (qual_wfl, "No variable `%s' defined in class `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + return 1; + } + + /* Check on accessibility here */ + if (not_accessible_p (type, field_decl, from_super)) + { + parse_error_context + (qual_wfl, + "Can't access %s field `%s.%s' from `%s'", + java_accstring_lookup + (get_access_flags_from_decl (field_decl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type))), + IDENTIFIER_POINTER (DECL_NAME (field_decl)), + IDENTIFIER_POINTER + (DECL_NAME (TYPE_NAME (current_class)))); + return 1; + } + + /* There are things to check when fields are accessed + from type. There are no restrictions on a static + declaration of the field when it is accessed from an + interface */ + is_static = FIELD_STATIC (field_decl); + if (!from_super && from_type + && !TYPE_INTERFACE_P (type) && !is_static) + { + parse_error_context + (qual_wfl, "Can't make a static reference to nonstatic " + "variable `%s' in class `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (qual_wfl)), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + return 1; + } + from_cast = from_super = 0; + + /* If we need to generate something to get a proper handle + on what this field is accessed from, do it now. */ + if (!is_static) + { + decl = maybe_access_field (decl, *where_found, type); + if (decl == error_mark_node) + return 1; + } + + /* We want to keep the location were found it, and the type + we found. */ + *where_found = decl; + *type_found = type; + + /* This is the decl found and eventually the next one to + search from */ + decl = field_decl; + } + + from_type = 0; + type = QUAL_DECL_TYPE (decl); + } + } + *found_decl = decl; + return 0; +} + +/* 6.6 Qualified name and access control. Returns 1 if MEMBER (a decl) + can't be accessed from REFERENCE (a record type). */ + +int not_accessible_p (reference, member, from_super) + tree reference, member; + int from_super; +{ + int access_flag = get_access_flags_from_decl (member); + + /* Access always granted for members declared public */ + if (access_flag & ACC_PUBLIC) + return 0; + + /* Check access on protected members */ + if (access_flag & ACC_PROTECTED) + { + /* Access granted if it occurs from within the package + containing the class in which the protected member is + declared */ + if (class_in_current_package (DECL_CONTEXT (member))) + return 0; + + if (TREE_CODE (member) == FUNCTION_DECL && DECL_CONSTRUCTOR_P (member)) + { + /* Access from SUPER is granted */ + if (from_super) + return 0; + /* Otherwise, access isn't granted */ + return 1; + } + else + { + /* If accessed with the form `super.member', then access is + granted */ + if (from_super) + return 0; + + /* Otherwise, access is granted if occuring from the class where + member is declared or a subclass of it */ + if (inherits_from_p (reference, current_class)) + return 0; + } + return 1; + } + + /* Check access on private members. Access is granted only if it + occurs from within the class in witch it is declared*/ + + if (access_flag & ACC_PRIVATE) + return (current_class == DECL_CONTEXT (member) ? 0 : 1); + + /* Default access are permitted only when occuring within the + package in which the type (REFERENCE) is declared. In other words, + REFERENCE is defined in the current package */ + if (ctxp->package) + return !class_in_current_package (reference); + + /* Otherwise, access is granted */ + return 0; +} + +/* Returns 1 if class was declared in the current package, 0 otherwise */ + +static int +class_in_current_package (class) + tree class; +{ + static tree cache = NULL_TREE; + int qualified_flag; + tree left; + + if (cache == class) + return 1; + + qualified_flag = QUALIFIED_P (DECL_NAME (TYPE_NAME (class))); + + /* If the current package is empty and the name of CLASS is + qualified, class isn't in the current package. If there is a + current package and the name of the CLASS is not qualified, class + isn't in the current package */ + if (!ctxp->package && qualified_flag || ctxp->package && !qualified_flag) + return 0; + + /* If there is not package and the name of CLASS isn't qualified, + they belong to the same unnamed package */ + if (!ctxp->package && !qualified_flag) + return 1; + + /* Compare the left part of the name of CLASS with the package name */ + breakdown_qualified (&left, NULL, DECL_NAME (TYPE_NAME (class))); + if (ctxp->package == left) + { + cache = class; + return 1; + } + return 0; +} + +/* This function may generate code to access DECL from WHERE. This is + done only if certain conditions meet. */ + +static tree +maybe_access_field (decl, where, type) + tree decl, where, type; +{ + if (DECL_P (decl) && decl != current_this + && (!(TREE_CODE (decl) != PARM_DECL + && FIELD_STATIC (decl))) + && !IDENTIFIER_LOCAL_VALUE (DECL_NAME (decl))) + decl = build_field_ref (where ? where : current_this, + type, DECL_NAME (decl)); + return decl; +} + +/* Build a method invocation statement, by patching PATCH. If non NULL + and according to the situation, PRIMARY and WHERE may be + used. IS_STATIC is set to 1 if the invoked function is static. */ + +static tree +patch_method_invocation_stmt (patch, primary, where, is_static) + tree patch, primary, where; + int *is_static; +{ + tree wfl = TREE_OPERAND (patch, 0); + tree args = TREE_OPERAND (patch, 1); + tree name = EXPR_WFL_NODE (wfl); + tree list, class_type; + + /* Should be overriden if everything goes well. Otherwise, if + something fails, it should keep this value. It stop the + evaluation of a bogus assignment. See java_complete_tree, + MODIFY_EXPR: for the reasons why we sometimes want to keep on + evaluating an assignment */ + TREE_TYPE (patch) = error_mark_node; + + /* Since lookup functions are messing with line numbers, save the + context now. */ + java_parser_context_save_global (); + + /* 15.11.1: Compile-Time Step 1: Determine Class or Interface to Search */ + + /* Resolution of qualified name, excluding constructors */ + if (QUALIFIED_P (name) && !CALL_CONSTRUCTOR_P (patch)) + { + tree class_decl, identifier, identifier_wfl; + /* Extract the last IDENTIFIER of the qualified + expression. This is a wfl and we will use it's location + data during error report. */ + identifier_wfl = cut_identifier_in_qualified (wfl); + identifier = EXPR_WFL_NODE (identifier_wfl); + + /* Given the context, IDENTIFIER is syntactically qualified + as a MethodName. We need to qualify what's before */ + qualify_ambiguous_name (wfl); + + /* Package resolution are erroneous */ + if (RESOLVE_PACKAGE_NAME_P (wfl)) + { + tree remainder; + breakdown_qualified (&remainder, NULL, EXPR_WFL_NODE (wfl)); + parse_error_context (wfl, "Can't search method `%s' in package " + "`%s'",IDENTIFIER_POINTER (identifier), + IDENTIFIER_POINTER (remainder)); + return error_mark_node; + } + /* We're resolving a call from a type */ + else if (RESOLVE_TYPE_NAME_P (wfl)) + { + tree decl = QUAL_RESOLUTION (EXPR_WFL_QUALIFICATION (wfl)); + tree name = DECL_NAME (decl); + tree type; + + class_decl = resolve_and_layout (name, wfl); + if (CLASS_INTERFACE (decl)) + { + parse_error_context + (identifier_wfl, "Can't make static reference to method " + "`%s' in interface `%s'", IDENTIFIER_POINTER (identifier), + IDENTIFIER_POINTER (name)); + return error_mark_node; + } + /* Look the method up in the type selector. The method ought + to be static. */ + type = TREE_TYPE (class_decl); + list = lookup_method_invoke (0, wfl, type, identifier, args); + if (list && !METHOD_STATIC (list)) + { + char *fct_name = strdup ((char *)lang_printable_name (list)); + parse_error_context + (identifier_wfl, + "Can't make static reference to method `%s %s' in class `%s'", + lang_printable_name (TREE_TYPE (TREE_TYPE (list))), fct_name, + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)))); + free (fct_name); + return error_mark_node; + } + } + /* We're resolving an expression name */ + else + { + tree field, type; + + /* 1- Find the field to which the call applies */ + field = resolve_field_access (wfl, NULL, &type); + if (field == error_mark_node) + return error_mark_node; + + /* 2- Do the layout of the class where the last field + was found, so we can search it. */ + class_decl = + resolve_and_layout (DECL_NAME (TYPE_NAME (type)), NULL_TREE); + + /* 3- Retrieve a filtered list of method matches, Refine + if necessary. In any cases, point out errors. */ + list = lookup_method_invoke (0, identifier_wfl, type, + identifier, args); + + /* 4- Add the field as an argument */ + args = tree_cons (NULL_TREE, field, args); + } + + /* CLASS_TYPE is used during the call to not_accessible_p and + IDENTIFIER_WFL will be used to report any problem further */ + class_type = TREE_TYPE (class_decl); + wfl = identifier_wfl; + } + /* Resolution of simple names, names generated after a primary: or + constructors */ + else + { + tree class_to_search; + int lc; /* Looking for Constructor */ + + /* We search constructor in their target class */ + if (CALL_CONSTRUCTOR_P (patch)) + { + class_to_search = resolve_no_layout (EXPR_WFL_NODE (wfl), NULL_TREE); + if (!class_to_search) + { + parse_error_context + (wfl, "Class `%s' not found in type declaration", + IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl))); + return error_mark_node; + } + + /* Can't instantiate an abstract class */ + if (CLASS_ABSTRACT (class_to_search)) + { + parse_error_context + (wfl, "Class `%s' is an abstract class. It can't be " + "instantiated", IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl))); + return error_mark_node; + } + class_to_search = TREE_TYPE (class_to_search); + lc = 1; + } + /* This is a regular search in the local class, unless an + alternate class is specified. */ + else + { + class_to_search = (where ? where : current_class); + lc = 0; + } + + /* NAME is a simple identifier or comes from a primary. Search + in the class whose declaration contain the method being + invoked. */ + list = lookup_method_invoke (lc, wfl, class_to_search, name, args); + + /* Don't continue if no method were found, as the next statement + can't be executed then. */ + if (!list) return error_mark_node; + + /* Check for static reference if non static methods */ + if (check_for_static_method_reference (wfl, patch, list, + class_to_search, primary)) + return error_mark_node; + + /* Non static/constructor methods are called with the current + object extra argument. If method is resolved as a primary, + use the primary otherwise use the current THIS. */ + if (!CALL_CONSTRUCTOR_P (patch) && !METHOD_STATIC (list)) + args = tree_cons (NULL_TREE, primary ? primary : current_this, args); + + class_type = class_to_search; + } + + /* Merge point of all resolution schemes. If we have nothing, this + is an error, already signaled */ + if (!list) return error_mark_node; + + /* Check accessibility, position the is_static flag, build and + return the call */ + if (not_accessible_p (class_type, list, 0)) + { + char *fct_name = strdup ((char *)lang_printable_name (list)); + parse_error_context + (wfl, "Can't access %s method `%s %s.%s' from `%s'", + java_accstring_lookup (get_access_flags_from_decl (list)), + lang_printable_name (TREE_TYPE (TREE_TYPE (list))), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class_type))), fct_name, + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (current_class)))); + free (fct_name); + return error_mark_node; + } + + if (is_static) + *is_static = METHOD_STATIC (list); + java_parser_context_restore_global (); + return patch_invoke (patch, list, args, wfl); +} + +/* Check that we're not trying to do a static reference to a method in + non static method. Return 1 if it's the case, 0 otherwise. */ + +static int +check_for_static_method_reference (wfl, node, method, where, primary) + tree wfl, node, method, where, primary; +{ + if (METHOD_STATIC (current_function_decl) + && !METHOD_STATIC (method) && !primary && !CALL_CONSTRUCTOR_P (node)) + { + char *fct_name = strdup ((char *)lang_printable_name (method)); + parse_error_context + (wfl, "Can't make static reference to method `%s %s' in class `%s'", + lang_printable_name (TREE_TYPE (TREE_TYPE (method))), fct_name, + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (where)))); + free (fct_name); + return 1; + } + return 0; +} + +/* Patch an invoke expression METHOD and ARGS, based on its invocation + mode. */ + +static tree +patch_invoke (patch, method, args, cl) + tree patch, method, args; + tree cl; +{ + tree dtable, func; + tree signature = build_java_signature (TREE_TYPE (method)); + tree original_call; + + switch (invocation_mode (method, 0)) + { + case INVOKE_VIRTUAL: + dtable = invoke_build_dtable (0, args); + func = build_invokevirtual (dtable, method); + break; + case INVOKE_STATIC: + func = build_known_method_ref (method, TREE_TYPE (method), + DECL_CONTEXT (method), + signature, args); + args = nreverse (args); + break; + + default: + fatal ("Unknown invocation mode - build_invoke"); + return NULL_TREE; + } + + + /* Ensure self_type is initialized, (invokestatic). FIXME */ + func = build1 (NOP_EXPR, build_pointer_type (TREE_TYPE (method)), func); + TREE_TYPE (patch) = TREE_TYPE (TREE_TYPE (method)); + TREE_OPERAND (patch, 0) = func; + TREE_OPERAND (patch, 1) = args; + original_call = patch; + + /* We're calling a constructor. New is called an its returned value + is an argument to the constructor. We build a COMPOUND_EXPR and + use saved expression so that the overall NEW expression value is + a pointer to a newly created and initialized class. */ + if (CALL_CONSTRUCTOR_P (original_call)) + { + tree class = DECL_CONTEXT (method); + tree c1, saved_new, size, new; + if (!TYPE_SIZE (class)) + safe_layout_class (class); + size = size_in_bytes (class); + new = build (CALL_EXPR, promote_type (class), + build_address_of (alloc_object_node), + tree_cons (NULL_TREE, build_class_ref (class), + build_tree_list (NULL_TREE, + size_in_bytes (class))), + NULL_TREE); + saved_new = save_expr (new); + c1 = build_tree_list (NULL_TREE, saved_new); + TREE_CHAIN (c1) = TREE_OPERAND (original_call, 1); + TREE_OPERAND (original_call, 1) = c1; + TREE_SET_CODE (original_call, CALL_EXPR); + patch = build (COMPOUND_EXPR, TREE_TYPE (new), patch, saved_new); + } + return patch; +} + +static int +invocation_mode (method, super) + tree method; + int super; +{ + int access = get_access_flags_from_decl (method); + + if (access & ACC_STATIC) + return INVOKE_STATIC; + + if (CLASS_FINAL (TYPE_NAME (DECL_CONTEXT (method)))) + return INVOKE_STATIC; + + if (super) + return INVOKE_SUPER; + + if (CLASS_INTERFACE (TYPE_NAME (DECL_CONTEXT (method)))) + return INVOKE_INTERFACE; + + if (DECL_CONSTRUCTOR_P (method)) + return INVOKE_STATIC; + + return INVOKE_VIRTUAL; +} + +/* Retrieve a refined list of matching methods. */ + +static tree +lookup_method_invoke (lc, cl, class, name, arg_list) + int lc; + tree cl; + tree class, name, arg_list; +{ + tree method = make_node (FUNCTION_TYPE); + tree arg_type_list = NULL_TREE; + tree signature, list, node, scratch; + + for (node = arg_list; node; node = TREE_CHAIN (node)) + { + tree current_arg; + current_arg = + build_tree_list (NULL_TREE, + promote_type (TREE_TYPE (TREE_VALUE (node)))); + arg_type_list = chainon (current_arg, arg_type_list); + } + TYPE_ARG_TYPES (method) = arg_type_list; + + if (!lc) + { + signature = build_java_argument_signature (method); + list = match_java_method (class, name, signature); + list = refine_accessible_methods_list (lc, list); + } + else + { + TREE_TYPE (method) = void_type_node; + signature = build_java_signature (method); + list = lookup_java_constructor (class, signature); + } + + if (!list) + { + parse_error_context (cl, "Can't find method `%s(%s)' in class `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (signature), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class)))); + return NULL_TREE; + } + + if (lc) + return list; + + if (TREE_CHAIN (list)) + { + tree most_specific_list = NULL_TREE; + tree current; + /* 15.11.2.2 Choose the Most Specific Method */ + for (current = list; current; current = TREE_CHAIN (current)) + { + tree rest; + tree method = TREE_VALUE (list); + tree class_from = DECL_CONTEXT (method); + for (rest = TREE_CHAIN (current); rest; rest = TREE_CHAIN (rest)) + { + tree other = TREE_VALUE (rest); + + /* METHOD can be declared more specific with regard to OTHER iif: + + - The class METHOD belongs can be converted to the + class OTHER belongs by method invocation conversion + (5.3). Since we're dealing with classes here, it is + covered by the identity conversion or the windening + primitive conversion. + + - The types of the arguments of METHOD can be + converted to the types of the arguments of OTHER by + method invocation conversion (5.3). */ + + if (valid_ref_assignconv_cast_p (class_from, + DECL_CONTEXT (other), 0) + && 1) /* Test on args non implemented */ + most_specific_list = tree_cons (NULL_TREE, method, + most_specific_list); + } + } + list = most_specific_list; + } + + if (!list || TREE_CHAIN (list)) + { + parse_error_context (cl, "Can't find method `%s(%s)' in class `%s'", + IDENTIFIER_POINTER (name), + IDENTIFIER_POINTER (signature), + IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (class)))); + return NULL_TREE; + } + + /* 15.11.3 Is the Chosen Method Appropriate ? */ + else + return TREE_VALUE (list); +} + +/* Refine accessible methods from the raw matching method list, as + specified in 15.11.4.3. Return a (possibly empty) new method + list. */ + +static tree +refine_accessible_methods_list (lc, list) + int lc; /* Looking for Constructor */ + tree list; +{ +#define ADD_TO_LIST_AND_CONTINUE \ + { \ + refined_list = tree_cons (NULL_TREE, method, refined_list); \ + continue; \ + } + tree node, refined_list = NULL_TREE; + tree current_class_name = DECL_NAME (TYPE_NAME (current_class)); + + for (node = list; node; node = TREE_CHAIN (node)) + { + int access, identical; + tree class_from, method, class_from_name; + + method = TREE_VALUE (node); + + /* Constructor not retained here, unless were specifically + looking for them. */ + if (lc && DECL_CONSTRUCTOR_P (method)) + ADD_TO_LIST_AND_CONTINUE; + + access = get_access_flags_from_decl (method); + class_from = DECL_CONTEXT (method); + class_from_name = DECL_NAME (TYPE_NAME (class_from)); + + identical = identical_subpath_p (current_class_name, class_from_name); + + /* Check accessibility of class_from from the current one: This + test has been already carried out when qualify_ambiguous_name + tried to resolve a type found in an other package. It is not + necessary to retest things here, the error has been already + reported. */ + + /* Public method are always OK */ + if (access & ACC_PUBLIC) + ADD_TO_LIST_AND_CONTINUE; + + /* Protected method access is OK if classes are from the + same package or part of the same inheritance lineage */ + if ((access & ACC_PROTECTED) + && (inherits_from_p (current_class, class_from) || identical)) + ADD_TO_LIST_AND_CONTINUE; + + /* Methods with default (package) access are OK if classes are + from the same default package. */ + if (identical || + (!QUALIFIED_P (class_from_name) && !QUALIFIED_P (current_class_name))) + ADD_TO_LIST_AND_CONTINUE; + + /* Private method accessible iff current class is the node where + the method is defined */ + if ((access & ACC_PRIVATE) && (class_from == current_class)) + ADD_TO_LIST_AND_CONTINUE; + } +#undef ADD_TO_LIST_AND_CONTINUE + return refined_list; +} + +/* Qualification routines */ + +static void +qualify_ambiguous_name (id) + tree id; +{ + tree qual, qual_wfl, name, decl, ptr_type, saved_current_class; + int again, super_found = 0, this_found = 0; + + /* We first qualify the first element, then derive qualification of + others based on the first one. If the first element is qualified + by a resolution (field or type), this resolution is stored in the + QUAL_RESOLUTION of the qual element being examined. We need to + save the current_class since the use of SUPER might change the + its value. */ + saved_current_class = current_class; + qual = EXPR_WFL_QUALIFICATION (id); + do { + + /* Simple qualified expression feature a qual_wfl that is a + WFL. Expression derived from a primary feature more complicated + things like a CALL_EXPR. Expression from primary need to be + worked out to extract the part on which the qualification will + take place. */ + qual_wfl = QUAL_WFL (qual); + switch (TREE_CODE (qual_wfl)) + { + case CALL_EXPR: + qual_wfl = TREE_OPERAND (qual_wfl, 0); + if (TREE_CODE (qual_wfl) != EXPR_WITH_FILE_LOCATION) + { + qual = EXPR_WFL_QUALIFICATION (qual_wfl); + qual_wfl = QUAL_WFL (qual); + } + break; + case JAVA_NEW_CLASS_EXPR: + case CONVERT_EXPR: + case ARRAY_REF: + qual_wfl = TREE_OPERAND (qual_wfl, 0); + break; + } + name = EXPR_WFL_NODE (qual_wfl); + ptr_type = current_class; + again = 0; + /* If we have a THIS (from a primary), we set the context accordingly */ + if (name == this_identifier_node) + { + qual = TREE_CHAIN (qual); + qual_wfl = QUAL_WFL (qual); + name = EXPR_WFL_NODE (qual_wfl); + this_found = 1; + } + /* If we have a SUPER, we set the context accordingly */ + if (name == super_identifier_node) + { + current_class = CLASSTYPE_SUPER (ptr_type); + /* Check that there is such a thing as a super class. If not, + return. The error will be caught later on, during the + resolution */ + if (!current_class) + { + current_class = saved_current_class; + return; + } + qual = TREE_CHAIN (qual); + /* Do one more interation to set things up */ + super_found = again = 1; + } + } while (again); + + /* If name appears within the scope of a location variable + declaration or parameter declaration, then it is an expression + name. We don't carry this test out if we're in the context of the + use of SUPER or THIS */ + + if (!this_found && !super_found && (decl = IDENTIFIER_LOCAL_VALUE (name))) + { + RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1; + QUAL_RESOLUTION (qual) = decl; + } + + /* If within the class/interface NAME was found to be used there + exists a (possibly inherited) field named NAME, then this is an + expression name. */ + else if ((decl = lookup_field_wrapper (ptr_type, name))) + { + RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1; + QUAL_RESOLUTION (qual) = decl; + } + + /* We reclassify NAME as a type name if: + - NAME is a class/interface declared within the compilation + unit containing NAME, + - NAME is imported via a single-type-import declaration, + - NAME is declared in an another compilation unit of the package + of the compilation unit containing NAME, + - NAME is declared by exactly on type-import-on-demand declaration + of the compilation unit containing NAME. */ + else if ((decl = resolve_and_layout (name, NULL_TREE))) + { + RESOLVE_TYPE_NAME_P (qual_wfl) = 1; + QUAL_RESOLUTION (qual) = decl; + } + + /* Method call are expression name */ + else if (TREE_CODE (QUAL_WFL (qual)) == CALL_EXPR) + RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1; + + /* Check here that NAME isn't declared by more than one + type-import-on-demand declaration of the compilation unit + containing NAME. FIXME */ + + /* Otherwise, NAME is reclassified as a package name */ + else + RESOLVE_PACKAGE_NAME_P (qual_wfl) = 1; + + /* Propagate the qualification accross other components of the + qualified name */ + for (qual = TREE_CHAIN (qual); qual; + qual_wfl = QUAL_WFL (qual), qual = TREE_CHAIN (qual)) + { + if (RESOLVE_PACKAGE_NAME_P (qual_wfl)) + RESOLVE_PACKAGE_NAME_P (QUAL_WFL (qual)) = 1; + else + RESOLVE_EXPRESSION_NAME_P (QUAL_WFL (qual)) = 1; + } + + /* Store the global qualification for the ambiguous part of ID back + into ID fields */ + if (RESOLVE_EXPRESSION_NAME_P (qual_wfl)) + RESOLVE_EXPRESSION_NAME_P (id) = 1; + else if (RESOLVE_TYPE_NAME_P (qual_wfl)) + RESOLVE_TYPE_NAME_P (id) = 1; + else if (RESOLVE_PACKAGE_NAME_P (qual_wfl)) + RESOLVE_PACKAGE_NAME_P (id) = 1; + + /* Restore the current class */ + current_class = saved_current_class; +} + +static int +breakdown_qualified (left, right, source) + tree *left, *right, source; +{ + char *p = IDENTIFIER_POINTER (source), *base; + int l = IDENTIFIER_LENGTH (source); + + /* Breakdown NAME into REMAINDER . IDENTIFIER */ + base = p; + p += (l-1); + while (*p != '.' && p != base) + p--; + + /* We didn't find a '.'. Return an error */ + if (p == base) + return 1; + + *p = '\0'; + if (right) + *right = get_identifier (p+1); + *left = get_identifier (IDENTIFIER_POINTER (source)); + *p = '.'; + + return 0; +} + +/* Return 1 if N1 and N2 have identical sub-path. */ + +static int +identical_subpath_p (n1, n2) + tree n1, n2; +{ + tree left1, left2; + + if (!QUALIFIED_P (n1) || !QUALIFIED_P (n2)) + return n1 == n2; + + breakdown_qualified (&left1, NULL, n1); + breakdown_qualified (&left2, NULL, n2); + + return left1 == left2; +} + +static int +not_initialized_as_it_should_p (decl) + tree decl; +{ + if (DECL_P (decl)) + { + if (TREE_CODE (decl) == FIELD_DECL + && METHOD_STATIC (current_function_decl)) + return 0; + return DECL_P (decl) && !INITIALIZED_P (decl); + } + return 0; +} + +/* Patch tree nodes in a function body. When a BLOCK is found, push + local variable decls if present. */ + +static tree +java_complete_tree (node) + tree node; +{ + tree nn, cn, wfl_op1, wfl_op2; + int flag, location; + + /* CONVERT_EXPR always has its type set, even though it needs to be + worked out */ + if (TREE_TYPE (node) && TREE_CODE (node) != CONVERT_EXPR) + return node; + + /* The switch block implements cases processing container nodes + first. Contained nodes are always written back. Leaves come + next and return a value. */ + switch (TREE_CODE (node)) + { + case BLOCK: + + /* 1- Block section. + Set the local values on decl names so we can identify them + faster when they're referenced. At that stage, identifiers + are legal so we don't check for declaration errors. */ + for (cn = BLOCK_EXPR_DECLS (node); cn; cn = TREE_CHAIN (cn)) + { + DECL_CONTEXT (cn) = current_function_decl; + IDENTIFIER_LOCAL_VALUE (DECL_NAME (cn)) = cn; + INITIALIZED_P (cn) = 0; + } + if (BLOCK_EXPR_BODY (node)) + { + BLOCK_EXPR_BODY (node) = java_complete_tree (BLOCK_EXPR_BODY (node)); + if (BLOCK_EXPR_BODY (node) == error_mark_node) + return error_mark_node; + } + /* Turn local bindings to null */ + for (cn = BLOCK_EXPR_DECLS (node); cn; cn = TREE_CHAIN (cn)) + IDENTIFIER_LOCAL_VALUE (DECL_NAME (cn)) = NULL_TREE; + + TREE_TYPE (node) = void_type_node; + break; + + /* 2- They are expressions but ultimately deal with statements */ + case LABELED_BLOCK_EXPR: + PUSH_LABELED_BLOCK (node); + if (LABELED_BLOCK_BODY (node)) + COMPLETE_CHECK_OP_1 (node); + TREE_TYPE (node) = void_type_node; + POP_LABELED_BLOCK (); + return node; + + case EXIT_BLOCK_EXPR: + /* We don't complete operand 1, because it's the return value of + the EXIT_BLOCK_EXPR which doesn't exist it Java */ + return patch_bc_statement (node); + + case LOOP_EXPR: + PUSH_LOOP (node); + /* Check whether the loop was enclosed in a labeled + statement. If not, create one, insert the loop in it and + return the node */ + nn = patch_loop_statement (node); + /* Anyways, walk the body of the loop */ + TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0)); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + TREE_TYPE (nn) = TREE_TYPE (node) = void_type_node; + /* If we returned something different, that's because we + inserted a label. Pop the label too. */ + if (nn != node) + POP_LABELED_BLOCK (); + POP_LOOP (); + return nn; + + case EXIT_EXPR: + TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0)); + return patch_exit_expr (node); + + case COND_EXPR: + /* Condition */ + TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0)); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + /* then-else branches */ + TREE_OPERAND (node, 1) = java_complete_tree (TREE_OPERAND (node, 1)); + if (TREE_OPERAND (node, 1) == error_mark_node) + return error_mark_node; + TREE_OPERAND (node, 2) = java_complete_tree (TREE_OPERAND (node, 2)); + if (TREE_OPERAND (node, 2) == error_mark_node) + return error_mark_node; + return patch_if_else_statement (node); + break; + + /* 3- Expression section */ + case COMPOUND_EXPR: + TREE_OPERAND (node, 0) = java_complete_tree (TREE_OPERAND (node, 0)); + TREE_OPERAND (node, 1) = java_complete_tree (TREE_OPERAND (node, 1)); + if (TREE_OPERAND (node, 1) == error_mark_node) + return error_mark_node; + TREE_TYPE (node) = TREE_TYPE (TREE_OPERAND (node, 1)); + break; + + case RETURN_EXPR: + return patch_return (node); + + case EXPR_WITH_FILE_LOCATION: + if (!EXPR_WFL_NODE (node) /* Or a PRIMARY flag ? */ + || TREE_CODE (EXPR_WFL_NODE (node)) == IDENTIFIER_NODE) + return resolve_expression_name (node); + else + { + EXPR_WFL_NODE (node) = java_complete_tree (EXPR_WFL_NODE (node)); + TREE_SIDE_EFFECTS (node) = 1; + if (EXPR_WFL_NODE (node) == error_mark_node) + { + /* Its important for the evaluation of assignment that + this mark on the TREE_TYPE is propagated. */ + TREE_TYPE (node) = error_mark_node; + return error_mark_node; + } + else + TREE_TYPE (node) = TREE_TYPE (EXPR_WFL_NODE (node)); + } + break; + + case JAVA_NEW_ARRAY_EXPR: + /* Patch all the dimensions */ + flag = 0; + for (cn = TREE_OPERAND (node, 1); cn; cn = TREE_CHAIN (cn)) + { + int location = EXPR_WFL_LINECOL (TREE_VALUE (cn)); + tree dim = java_complete_tree (TREE_VALUE (cn)); + if (dim == error_mark_node) + { + flag = 1; + continue; + } + else + { + TREE_VALUE (cn) = save_expr (dim); + /* Setup the location of the current dimension, for + later error report. */ + TREE_PURPOSE (cn) = + build_expr_wfl (NULL_TREE, input_filename, 0, 0); + EXPR_WFL_LINECOL (TREE_PURPOSE (cn)) = location; + } + } + /* They complete the array creation expression, if no errors + were found. */ + return (flag ? error_mark_node : patch_newarray (node)); + + case JAVA_NEW_CLASS_EXPR: + case CALL_EXPR: + /* Complete function's argument first */ + if (complete_function_arguments (node)) + return error_mark_node; + else + return patch_method_invocation_stmt (node, NULL_TREE, NULL_TREE, NULL); + + case MODIFY_EXPR: + /* Save potential wfls */ + wfl_op1 = TREE_OPERAND (node, 0); + wfl_op2 = TREE_OPERAND (node, 1); + TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + + if (COMPOUND_ASSIGN_P (wfl_op2)) + { + tree lvalue; + tree other = + java_complete_tree (TREE_OPERAND (wfl_op2, 0)); + + /* Hand stablize the lhs on both places */ + lvalue = stabilize_reference (other); + TREE_OPERAND (node, 0) = lvalue; + TREE_OPERAND (TREE_OPERAND (node, 1), 0) = lvalue; + } + + /* There are cases where the type of RHS is fixed. In those + cases, if the evaluation of the RHS fails, we further the + evaluation of the assignment to detect more errors. */ + nn = java_complete_tree (TREE_OPERAND (node, 1)); + if (nn == error_mark_node) + { + /* It's hopeless, but we can further things on to discover + an error during the assignment. In any cases, the + assignment operation fails. */ + if (TREE_CODE (TREE_OPERAND (node, 1)) != EXPR_WITH_FILE_LOCATION + && TREE_TYPE (TREE_OPERAND (node, 1)) != error_mark_node) + patch_assignment (node, wfl_op1, wfl_op2); + + /* Now, we still mark the lhs as initialized */ + if (DECL_P (TREE_OPERAND (node, 0))) + INITIALIZED_P (TREE_OPERAND (node, 0)) = 1; + + return error_mark_node; + } + TREE_OPERAND (node, 1) = nn; + return patch_assignment (node, wfl_op1, wfl_op2); + + case MULT_EXPR: + case PLUS_EXPR: + case MINUS_EXPR: + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case URSHIFT_EXPR: + case BIT_AND_EXPR: + case BIT_XOR_EXPR: + case BIT_IOR_EXPR: + case TRUNC_MOD_EXPR: + case RDIV_EXPR: + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case EQ_EXPR: + case NE_EXPR: + case GT_EXPR: + case GE_EXPR: + case LT_EXPR: + case LE_EXPR: + /* Operands 0 and 1 are WFL in certain cases only. patch_binop + knows how to handle those cases. */ + wfl_op1 = TREE_OPERAND (node, 0); + wfl_op2 = TREE_OPERAND (node, 1); + TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + TREE_OPERAND (node, 1) = java_complete_tree (wfl_op2); + if (TREE_OPERAND (node, 1) == error_mark_node) + return error_mark_node; + return patch_binop (node, wfl_op1, wfl_op2); + + case JAVA_UNARY_PLUS_EXPR: + case NEGATE_EXPR: + case TRUTH_NOT_EXPR: + case BIT_NOT_EXPR: + case PREDECREMENT_EXPR: + case PREINCREMENT_EXPR: + case POSTDECREMENT_EXPR: + case POSTINCREMENT_EXPR: + case CONVERT_EXPR: + /* There are cases were wfl_op1 is a WFL. patch_unaryop knows + how to handle those cases. */ + wfl_op1 = TREE_OPERAND (node, 0); + TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + return patch_unaryop (node, wfl_op1); + + case ARRAY_REF: + /* There are cases were wfl_op1 is a WFL. patch_array_ref knows + how to handle those cases. */ + wfl_op1 = TREE_OPERAND (node, 0); + TREE_OPERAND (node, 0) = java_complete_tree (wfl_op1); + if (TREE_OPERAND (node, 0) == error_mark_node) + return error_mark_node; + /* The same applies to wfl_op2 */ + wfl_op2 = TREE_OPERAND (node, 1); + TREE_OPERAND (node, 1) = java_complete_tree (wfl_op2); + if (TREE_OPERAND (node, 1) == error_mark_node) + return error_mark_node; + return patch_array_ref (node, wfl_op1, wfl_op2); + + case JAVA_THIS_EXPR: + /* Can't use THIS in a static environment */ + if (!current_this) + { + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + parse_error_context (wfl_operator, "Keyword `this' used outside " + "allowed context"); + TREE_TYPE (node) = error_mark_node; + return error_mark_node; + } + return current_this; + + case STRING_CST: + /* Build the internal string representation */ + push_obstacks (&permanent_obstack, &permanent_obstack); + node = get_identifier (TREE_STRING_POINTER (node)); + location = alloc_name_constant (CONSTANT_String, node); + node = build_ref_from_constant_pool (location); + TREE_TYPE (node) = promote_type (string_type_node); + return node; + + default: + fatal ("No case for tree code `%s' - java_complete_tree\n", + tree_code_name [TREE_CODE (node)]); + } + return node; +} + +/* Complete function call's argument. Return a non zero value is an + error was found. */ + +static int +complete_function_arguments (node) + tree node; +{ + int flag = 0; + tree cn; + + for (cn = TREE_OPERAND (node, 1); cn; cn = TREE_CHAIN (cn)) + { + tree wfl = TREE_VALUE (cn), parm; + parm = java_complete_tree (wfl); + if (parm == error_mark_node) + { + flag = 1; + continue; + } + if (TREE_CODE (TREE_TYPE (parm)) == RECORD_TYPE) + TREE_VALUE (cn) = convert (promote_type (TREE_TYPE (parm)), parm); + else + TREE_VALUE (cn) = save_expr (parm); + if (not_initialized_as_it_should_p (parm)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl, EXPR_WFL_NODE (wfl)); + INITIALIZED_P (parm) = 1; + } + } + return flag; +} + +/* Sometimes (for loops and variable initialized during their + declaration), we want to wrap a statement around a WFL and turn it + debugable. */ + +static tree +build_debugable_stmt (location, stmt) + int location; + tree stmt; +{ + if (TREE_CODE (stmt) != EXPR_WITH_FILE_LOCATION) + { + stmt = build_expr_wfl (stmt, input_filename, 0, 0); + EXPR_WFL_LINECOL (stmt) = location; + } + JAVA_MAYBE_GENERATE_DEBUG_INFO (stmt); + return stmt; +} + +static tree +build_expr_block (body, decls) + tree body, decls; +{ + tree node = make_node (BLOCK); + BLOCK_EXPR_DECLS (node) = decls; + BLOCK_EXPR_BODY (body); + if (body) + TREE_TYPE (node) = TREE_TYPE (body); + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* Create a new function block and link its supercontext to the + previous block. The current function DECL is used as supercontext + when enter_block is called for the first time for a given + function. The current function body (DECL_FUNCTION_BODY) is set to + the newly created block. */ + +static block_level = 0; + +static tree +enter_block () +{ + tree b = build_expr_block (NULL_TREE, NULL_TREE); + tree fndecl = current_function_decl; + + if (!DECL_FUNCTION_BODY (fndecl)) + { + BLOCK_SUPERCONTEXT (b) = fndecl; + DECL_FUNCTION_BODY (fndecl) = b; + } + else + { + BLOCK_SUPERCONTEXT (b) = DECL_FUNCTION_BODY (fndecl); + DECL_FUNCTION_BODY (fndecl) = b; + } + return b; +} + +/* Exit a block by changing the current function body + (DECL_FUNCTION_BODY) to the current block super context, only if + the block being exited isn't the method's top level one. */ + +static tree +exit_block () +{ + tree b = DECL_FUNCTION_BODY (current_function_decl); + + if (BLOCK_SUPERCONTEXT (b) != current_function_decl) + DECL_FUNCTION_BODY (current_function_decl) = BLOCK_SUPERCONTEXT (b); + + return b; +} + +/* Lookup for NAME in the nested function's blocks, all the way up to + the current toplevel one. It complies with Java's local variable + scoping rules. */ + +static tree +lookup_name_in_blocks (name) + tree name; +{ + tree b = DECL_FUNCTION_BODY (current_function_decl); + + while (b != current_function_decl) + { + tree current; + + /* Paranoid sanity check. To be removed */ + if (TREE_CODE (b) != BLOCK) + fatal ("non block expr function body - lookup_name_in_blocks"); + + for (current = BLOCK_EXPR_DECLS (b); current; + current = TREE_CHAIN (current)) + if (DECL_NAME (current) == name) + return current; + b = BLOCK_SUPERCONTEXT (b); + } + return NULL_TREE; +} + +static void +maybe_absorb_scoping_blocks () +{ + while (BLOCK_EXPR_ORIGIN (DECL_FUNCTION_BODY (current_function_decl))) + { + tree b = exit_block (); + java_method_add_stmt (current_function_decl, b); + SOURCE_FRONTEND_DEBUG (("Absorbing scoping block at line %d", lineno)); + } +} + + +/* This section of the source is reserved to build_* functions that + are building incomplete tree nodes and the patch_* functions that + are completing them. */ + +/* Build an incomplete CALL_EXPR node. Encapsulate it within a WFL */ + +static tree +build_method_invocation (name, args) + tree name; + tree args; +{ + tree call = build (CALL_EXPR, NULL_TREE, name, args, NULL_TREE); + TREE_SIDE_EFFECTS (call) = 1; + /* Check on cases where NAME isn't a WFL. FIXME */ + EXPR_WFL_LINECOL (call) = EXPR_WFL_LINECOL (name); + return call; +} + +/* Build an incomplete assignment expression. */ + +static tree +build_assignment (op, op_location, lhs, rhs) + int op, op_location; + tree lhs, rhs; +{ + tree assignment; + /* Build the corresponding binop if we deal with a Compound + Assignment operator. Mark the binop sub-tree as part of a + Compound Assignment expression */ + if (op != ASSIGN_TK) + { + rhs = build_binop (BINOP_LOOKUP (op), op_location, lhs, rhs); + COMPOUND_ASSIGN_P (rhs) = 1; + } + assignment = build (MODIFY_EXPR, NULL_TREE, lhs, rhs); + TREE_SIDE_EFFECTS (assignment) = 1; + EXPR_WFL_LINECOL (assignment) = op_location; + return assignment; +} + +/* Print an INTEGER_CST node in a static buffer, and return the buffer. */ + +static char * +print_int_node (node) + tree node; +{ + static char buffer [80]; + if (TREE_CONSTANT_OVERFLOW (node)) + sprintf (buffer, ""); + + if (TREE_INT_CST_HIGH (node) == 0) + sprintf (buffer, HOST_WIDE_INT_PRINT_UNSIGNED, + TREE_INT_CST_LOW (node)); + else if (TREE_INT_CST_HIGH (node) == -1 + && TREE_INT_CST_LOW (node) != 0) + { + buffer [0] = '-'; + sprintf (&buffer [1], HOST_WIDE_INT_PRINT_UNSIGNED, + -TREE_INT_CST_LOW (node)); + } + else + sprintf (buffer, HOST_WIDE_INT_PRINT_DOUBLE_HEX, + TREE_INT_CST_HIGH (node), TREE_INT_CST_LOW (node)); + + return buffer; +} + +/* 15.25 Assignment operators. */ + +static tree +patch_assignment (node, wfl_op1, wfl_op2) + tree node; + tree wfl_op1; + tree wfl_op2; +{ + tree rhs = TREE_OPERAND (node, 1); + tree lvalue = TREE_OPERAND (node, 0); + tree lhs_type, rhs_type, new_rhs = NULL_TREE; + int all_primitive; + int error_found = 0; + int lvalue_from_array = 0; + + /* Can't assign to a final. */ + if (DECL_P (lvalue) && FIELD_FINAL (lvalue)) + { + parse_error_context + (wfl_op1, "Can't assign a value to the final variable `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl_op1))); + error_found = 1; + } + + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* Lhs can be a named variable */ + if (DECL_P (lvalue)) + { + INITIALIZED_P (lvalue) = 1; + lhs_type = TREE_TYPE (lvalue); + } + /* Or Lhs can be a array acccess. Should that be lvalue ? FIXME + + comment on reason why */ + else if (TREE_CODE (wfl_op1) == ARRAY_REF) + { + lhs_type = TREE_TYPE (lvalue); + lvalue_from_array = 1; + } + /* Or a field access */ + else if (TREE_CODE (lvalue) == COMPONENT_REF) + lhs_type = TREE_TYPE (lvalue); + /* Or a function return slot */ + else if (TREE_CODE (lvalue) == RESULT_DECL) + lhs_type = TREE_TYPE (lvalue); + /* Otherwise, this is an error */ + else + { + parse_error_context (wfl_op1, "Invalid left hand side of assignment"); + error_found = 1; + } + + rhs_type = TREE_TYPE (rhs); + + /* 5.2 Begin Assignment conversion */ + + /* 5.1.1 Try Identity Conversion */ + if (lhs_type == rhs_type) + new_rhs = rhs; + + /* 5.1.2 Try Widening Primitive Conversion */ + all_primitive = JPRIMITIVE_TYPE_P (lhs_type) && JPRIMITIVE_TYPE_P (rhs_type); + if (all_primitive && JINTEGRAL_TYPE_P (rhs_type) + && ((TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type)) + || (JFLOAT_TYPE_P (lhs_type) && + TYPE_PRECISION (rhs_type) == TYPE_PRECISION (lhs_type)))) + new_rhs = convert (lhs_type, rhs); + else if (all_primitive && JFLOAT_TYPE_P (rhs_type) + && (TYPE_PRECISION (rhs_type) < TYPE_PRECISION (lhs_type))) + new_rhs = convert (lhs_type, rhs); + + /* Try a narrowing primitive conversion: + - expression is a constant expression of type int AND + - variable is byte, short or char AND + - The value of the expression is representable in the type of the + variable */ + else if (rhs_type == int_type_node && TREE_CONSTANT (rhs) + && (lhs_type == byte_type_node || lhs_type == char_type_node + || lhs_type == short_type_node)) + { + if (int_fits_type_p (rhs, lhs_type)) + new_rhs = convert (lhs_type, rhs); + else + parse_warning_context + (wfl_op1, "Constant expression `%s' to wide for narrowing " + "primitive conversion to `%s'", + print_int_node (rhs), lang_printable_name (lhs_type)); + /* Reported a warning that will turn into an error further + down, so we don't return */ + } + + /* 5.2 Try a reference conversion */ + else if (!JPRIMITIVE_TYPE_P (rhs_type) && JREFERENCE_TYPE_P (lhs_type)) + { + /* `null' may be assigned to any reference type */ + if (rhs == null_pointer_node) + new_rhs = null_pointer_node; + /* Try the reference assignment conversion */ + else if (valid_ref_assignconv_cast_p (rhs_type, lhs_type, 0)) + new_rhs = rhs; + if (new_rhs) + lhs_type = promote_type (rhs_type); + } + + /* 15.25.2 If we have a compound assignment, convert RHS into the + type of the LHS */ + else if (COMPOUND_ASSIGN_P (TREE_OPERAND (node, 1))) + new_rhs = convert (lhs_type, rhs); + + /* Explicit cast required. This is an error */ + if (!new_rhs) + { + char *t1 = strdup ((char *)lang_printable_name (TREE_TYPE (rhs))); + char *t2 = strdup ((char *)lang_printable_name (lhs_type)); + tree wfl; + char operation [32]; /* Max size known */ + + /* If the assignment is part of a declaration, we use the WFL of + the declared variable to point out the error and call it a + declaration problem. If the assignment is a genuine = + operator, we call is a operator `=' problem, otherwise we + call it an assignment problem. In both of these last cases, + we use the WFL of the operator to indicate the error. */ + + if (MODIFY_EXPR_FROM_INITIALIZATION_P (node)) + { + wfl = wfl_op1; + strcpy (operation, "declaration"); + } + else + { + wfl = wfl_operator; + if (COMPOUND_ASSIGN_P (TREE_OPERAND (node, 1))) + strcpy (operation, "assignment"); + else if (TREE_CODE (TREE_OPERAND (node, 0)) == RESULT_DECL) + strcpy (operation, "`return'"); + else + strcpy (operation, "`='"); + } + + parse_error_context + (wfl, (!can_cast_to_p (rhs_type, lhs_type) ? + "Incompatible type for %s. Can't convert `%s' to `%s'" : + "Incompatible type for %s. Explicit cast " + "needed to convert `%s' to `%s'"), operation, t1, t2); + free (t1); free (t2); + error_found = 1; + } + + /* Before reporting type incompatibility errors, check that the rhs + is initialized, if a variable */ + if (not_initialized_as_it_should_p (rhs)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_op2, DECL_NAME (rhs)); + INITIALIZED_P (rhs) = 1; + } + + if (error_found) + return error_mark_node; + + /* If we built a compound expression as the result of a reference + assignment into an array element, return it here. */ + if (TREE_CODE (node) == COMPOUND_EXPR) + return node; + + TREE_OPERAND (node, 0) = lvalue; + TREE_OPERAND (node, 1) = new_rhs; + TREE_TYPE (node) = lhs_type; + return node; +} + +/* Check that SOURCE can be converted into DEST, at least with a + cast. If the convertion can't occur at all, return 0 otherwise + 1. This function is used to produce accurate error messages on the + reasons why an assignment failed. */ + +static int +can_cast_to_p (source, dest) + tree source; + tree dest; +{ + if (TREE_CODE (source) == POINTER_TYPE) + source = TREE_TYPE (source); + if (TREE_CODE (dest) == POINTER_TYPE) + dest = TREE_TYPE (dest); + + if (TREE_CODE (source) == RECORD_TYPE && TREE_CODE (dest) == RECORD_TYPE) + return valid_ref_assignconv_cast_p (source, dest, 1); + + else if (JNUMERIC_TYPE_P (source) && JNUMERIC_TYPE_P (dest)) + return 1; + + return 0; +} + +/* Check that something of SOURCE type can be assigned or cast to + something of DEST type at runtime. Return 1 if the operation is + valid, 0 otherwise. If CAST is set to 1, we're treating the case + were SOURCE is cast into DEST, which borrows a lot of the + assignment check. */ + +static int +valid_ref_assignconv_cast_p (source, dest, cast) + tree source; + tree dest; + int cast; +{ + if (TREE_CODE (source) == POINTER_TYPE) + source = TREE_TYPE (source); + if (TREE_CODE (dest) == POINTER_TYPE) + dest = TREE_TYPE (dest); + /* Case where SOURCE is a class type */ + if (TYPE_CLASS_P (source)) + { + if (TYPE_CLASS_P (dest)) + return source == dest || inherits_from_p (source, dest) + || cast && inherits_from_p (dest, source); + if (TYPE_INTERFACE_P (dest)) + { + /* If doing a cast and SOURCE is final, the operation is + always correct a compile time (because even if SOURCE + does not implement DEST, a subclass of SOURCE might). */ + if (cast && !CLASS_FINAL (TYPE_NAME (source))) + return 1; + /* Otherwise, SOURCE must implement DEST */ + return interface_of_p (dest, source); + } + /* DEST is an array, cast permited if SOURCE is of Object type */ + return (cast && source == object_type_node ? 1 : 0); + } + if (TYPE_INTERFACE_P (source)) + { + if (TYPE_CLASS_P (dest)) + { + /* If not casting, DEST must be the Object type */ + if (!cast) + return dest == object_type_node; + /* We're doing a cast. The cast is always valid is class + DEST is not final, otherwise, DEST must implement SOURCE */ + else if (!CLASS_FINAL (TYPE_NAME (source))) + return 1; + else + return interface_of_p (source, dest); + } + if (TYPE_INTERFACE_P (dest)) + { + /* If doing a cast, then if SOURCE and DEST contain method + with the same signature but different return type, then + this is a (compile time) error */ + if (cast) + { + tree method_source, method_dest; + tree source_type; + tree source_sig, dest_sig; + tree source_name; + for (method_source = TYPE_METHODS (source); method_source; + method_source = TREE_CHAIN (method_source)) + { + source_sig = + build_java_argument_signature (TREE_TYPE (method_source)); + source_type = TREE_TYPE (TREE_TYPE (method_source)); + source_name = DECL_NAME (method_source); + for (method_dest = TYPE_METHODS (dest); + method_dest; method_dest = TREE_CHAIN (method_dest)) + if (source_sig == + build_java_argument_signature (TREE_TYPE (method_dest)) + && source_name == DECL_NAME (method_dest) + && source_type != TREE_TYPE (TREE_TYPE (method_dest))) + return 0; + } + return 1; + } + else + return source == dest || interface_of_p (dest, source); + } + else /* Array */ + return 0; + } + if (TYPE_ARRAY_P (source)) + { + if (TYPE_CLASS_P (dest)) + return dest == object_type_node; + if (TYPE_INTERFACE_P (dest)) + return 0; /* Install test on Clonable. FIXME */ + else /* Arrays */ + { + tree source_element_type = TYPE_ARRAY_ELEMENT (source); + tree dest_element_type = TYPE_ARRAY_ELEMENT (dest); + + if (source_element_type == dest_element_type) + return 1; + return valid_ref_assignconv_cast_p (source_element_type, + dest_element_type, cast); + } + return 0; + } + return 0; +} + +/* Build an incomplete binop expression. */ + +static tree +build_binop (op, op_location, op1, op2) + enum tree_code op; + int op_location; + tree op1, op2; +{ + tree wfl; + + /* URSHIFT_EXPR is not part of what GCC understands, we can't directly build + a node with it */ + tree binop = + build ((op == URSHIFT_EXPR ? RSHIFT_EXPR : op), NULL_TREE, op1, op2); + if (op == URSHIFT_EXPR) + TREE_SET_CODE (binop, op); + + TREE_SIDE_EFFECTS (binop) = 1; + /* Store the location of the operator, for better error report. The + string of the operator will be rebuild based on the OP value. */ + EXPR_WFL_LINECOL (binop) = op_location; + return binop; +} + +/* Build the string of the operator retained by NODE. If NODE is part + of a compound expression, add an '=' at the end of the string. This + function is called when an error needs to be reported on an + operator. The string is returned as a pointer to a static character + buffer. */ + +static char * +operator_string (node) + tree node; +{ +#define BUILD_OPERATOR_STRING(S) \ + { \ + sprintf (buffer, "%s%s", S, (COMPOUND_ASSIGN_P (node) ? "=" : "")); \ + return buffer; \ + } + + static char buffer [10]; + switch (TREE_CODE (node)) + { + case MULT_EXPR: BUILD_OPERATOR_STRING ("*"); + case RDIV_EXPR: BUILD_OPERATOR_STRING ("/"); + case TRUNC_MOD_EXPR: BUILD_OPERATOR_STRING ("%"); + case PLUS_EXPR: BUILD_OPERATOR_STRING ("+"); + case MINUS_EXPR: BUILD_OPERATOR_STRING ("-"); + case LSHIFT_EXPR: BUILD_OPERATOR_STRING ("<<"); + case RSHIFT_EXPR: BUILD_OPERATOR_STRING (">>"); + case URSHIFT_EXPR: BUILD_OPERATOR_STRING (">>>"); + case BIT_AND_EXPR: BUILD_OPERATOR_STRING ("&"); + case BIT_XOR_EXPR: BUILD_OPERATOR_STRING ("^"); + case BIT_IOR_EXPR: BUILD_OPERATOR_STRING ("|"); + case TRUTH_ANDIF_EXPR: BUILD_OPERATOR_STRING ("&&"); + case TRUTH_ORIF_EXPR: BUILD_OPERATOR_STRING ("||"); + case EQ_EXPR: BUILD_OPERATOR_STRING ("=="); + case NE_EXPR: BUILD_OPERATOR_STRING ("!="); + case GT_EXPR: BUILD_OPERATOR_STRING (">"); + case GE_EXPR: BUILD_OPERATOR_STRING (">="); + case LT_EXPR: BUILD_OPERATOR_STRING ("<"); + case LE_EXPR: BUILD_OPERATOR_STRING ("<="); + case JAVA_UNARY_PLUS_EXPR: BUILD_OPERATOR_STRING ("+"); + case NEGATE_EXPR: BUILD_OPERATOR_STRING ("-"); + case TRUTH_NOT_EXPR: BUILD_OPERATOR_STRING ("!"); + case BIT_NOT_EXPR: BUILD_OPERATOR_STRING ("~"); + case PREINCREMENT_EXPR: /* Fall through */ + case POSTINCREMENT_EXPR: BUILD_OPERATOR_STRING ("++"); + case PREDECREMENT_EXPR: /* Fall through */ + case POSTDECREMENT_EXPR: BUILD_OPERATOR_STRING ("--"); + default: + fatal ("unregistered operator %s - operator_string", + tree_code_name [TREE_CODE (node)]); + } + return NULL; +#undef BUILD_OPERATOR_STRING +} + +/* Binary operators (15.16 up to 15.18). We return error_mark_node on + errors but we modify NODE so that it contains the type computed + according to the expression, when it's fixed. Otherwise, we write + error_mark_node as the type. It allows us to further the analysis + of remaining nodes and detects more errors in certain cases. */ + +static tree +patch_binop (node, wfl_op1, wfl_op2) + tree node; + tree wfl_op1; + tree wfl_op2; +{ + tree op1 = TREE_OPERAND (node, 0); + tree op2 = TREE_OPERAND (node, 1); + tree op1_type = TREE_TYPE (op1); + tree op2_type = TREE_TYPE (op2); + tree prom_type; + int code = TREE_CODE (node); + /* If 1, tell the routine that we have to return error_mark_node + after checking for the initialization of the RHS */ + int error_found = 0; + + /* Figure what is going to be checked first for initialization prior + its use. If NODE is part of a compound assignment, we check the + second operand first, otherwise the first one first. We also + initialize the matching WFL for the error report. `cfi' stands + for Check For Initialization */ + tree cfi = (COMPOUND_ASSIGN_P (node) ? op2 : op1); + tree cfi_wfl = (COMPOUND_ASSIGN_P (node) ? wfl_op2 : wfl_op1); + + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* Check initialization of LHS first. We then silence further error + message if the variable wasn't initialized */ + if (not_initialized_as_it_should_p (cfi)) + { + ERROR_VARIABLE_NOT_INITIALIZED (cfi_wfl, DECL_NAME (cfi)); + INITIALIZED_P (op1) = 1; + } + + switch (code) + { + /* 15.16 Multiplicative operators */ + case MULT_EXPR: /* 15.16.1 Multiplication Operator * */ + case RDIV_EXPR: /* 15.16.2 Division Operator / */ + case TRUNC_MOD_EXPR: /* 15.16.3 Remainder operator % */ + if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type)) + { + if (!JPRIMITIVE_TYPE_P (op1_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op1_type); + if (!JPRIMITIVE_TYPE_P (op2_type) && (op1_type != op2_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op2_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + break; + } + prom_type = binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + /* Change the division operator if necessary */ + if (code == RDIV_EXPR && TREE_CODE (prom_type) == INTEGER_TYPE) + TREE_SET_CODE (node, TRUNC_DIV_EXPR); + /* This one is more complicated. FLOATs are processed by a function + call to soft_fmod. */ + if (code == TRUNC_MOD_EXPR) + return build_java_binop (TRUNC_MOD_EXPR, prom_type, op1, op2); + break; + + /* 15.17 Additive Operators */ + case PLUS_EXPR: /* 15.17.1 String Concatenation Operator + */ + if (JSTRING_TYPE_P (op1_type) || JSTRING_TYPE_P (op2_type)) + fatal ("operator `+' non implemented on String - patch_binop"); + case MINUS_EXPR: /* 15.17.2 Additive Operators (+ and -) for + Numeric Types */ + if (!JPRIMITIVE_TYPE_P (op1_type) || !JPRIMITIVE_TYPE_P (op2_type)) + { + if (!JPRIMITIVE_TYPE_P (op1_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op1_type); + if (!JPRIMITIVE_TYPE_P (op2_type) && (op1_type != op2_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op2_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + break; + } + prom_type = binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + break; + + /* 15.18 Shift Operators */ + case LSHIFT_EXPR: + case RSHIFT_EXPR: + case URSHIFT_EXPR: + if (!JINTEGRAL_TYPE_P (op1_type) || !JINTEGRAL_TYPE_P (op2_type)) + { + if (!JINTEGRAL_TYPE_P (op1_type)) + ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op1_type); + else + parse_error_context + (wfl_operator, (JPRIMITIVE_TYPE_P (op2_type) ? + "Incompatible type for `%s'. Explicit cast needed to convert " + "shift distance from `%s' to integral" : + "Incompatible type for `%s'. Can't convert shift distance from " + "`%s' to integral"), + operator_string (node), lang_printable_name (op2_type)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + break; + } + + /* Unary numeric promotion (5.6.1) is performed on each operand + separatly */ + op1 = convert (promote_type (op1_type), op1); + op2 = convert (promote_type (op2_type), op2); + + /* The type of the shift expression is the type of the promoted + type of the left-hand operand */ + prom_type = TREE_TYPE (op1); + + /* Shift int only up to 0x1f and long up to 0x3f */ + if (prom_type == int_type_node) + op2 = fold (build (BIT_AND_EXPR, int_type_node, op2, + build_int_2 (0x1f, 0))); + else + op2 = fold (build (BIT_AND_EXPR, int_type_node, op2, + build_int_2 (0x3f, 0))); + + /* The >>> operator is a >> operating on unsigned quantities */ + if (code == URSHIFT_EXPR) + { + op1 = convert (unsigned_type (prom_type), op1); + TREE_SET_CODE (node, RSHIFT_EXPR); + } + break; + + + /* 15.21 Bitwise and Logical Operators */ + case BIT_AND_EXPR: + case BIT_XOR_EXPR: + case BIT_IOR_EXPR: + if (JINTEGRAL_TYPE_P (op1_type) && JINTEGRAL_TYPE_P (op2_type)) + /* Binary numeric promotion is performed on both operand and the + expression retain that type */ + prom_type = binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + + else if (TREE_CODE (op1_type) == BOOLEAN_TYPE + && TREE_CODE (op1_type) == BOOLEAN_TYPE) + /* The type of the bitwise operator expression is BOOLEAN */ + prom_type = boolean_type_node; + else + { + if (!JINTEGRAL_TYPE_P (op1_type)) + ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op1_type); + if (!JINTEGRAL_TYPE_P (op2_type) && (op1_type != op2_type)) + ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op2_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + /* Insert a break here if adding thing before the switch's + break for this case */ + } + break; + + /* 15.22 Conditional-And Operator */ + case TRUTH_ANDIF_EXPR: + /* 15.23 Conditional-Or Operator */ + case TRUTH_ORIF_EXPR: + /* Operands must be of BOOLEAN type */ + if (TREE_CODE (op1_type) != BOOLEAN_TYPE || + TREE_CODE (op2_type) != BOOLEAN_TYPE) + { + if (TREE_CODE (op1_type) != BOOLEAN_TYPE) + ERROR_CANT_CONVERT_TO_BOOLEAN (wfl_operator, node, op1_type); + if (TREE_CODE (op2_type) != BOOLEAN_TYPE && (op1_type != op2_type)) + ERROR_CANT_CONVERT_TO_BOOLEAN (wfl_operator, node, op2_type); + TREE_TYPE (node) = boolean_type_node; + error_found = 1; + break; + } + /* The type of the conditional operators is BOOLEAN */ + prom_type = boolean_type_node; + break; + + /* 15.19.1 Numerical Comparison Operators <, <=, >, >= */ + case LT_EXPR: + case GT_EXPR: + case LE_EXPR: + case GE_EXPR: + /* The type of each of the operands must be a primitive numeric + type */ + if (!JNUMERIC_TYPE_P (op1_type) || ! JNUMERIC_TYPE_P (op2_type)) + { + if (!JNUMERIC_TYPE_P (op1_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op1_type); + if (!JNUMERIC_TYPE_P (op2_type) && (op1_type != op2_type)) + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op2_type); + TREE_TYPE (node) = boolean_type_node; + error_found = 1; + break; + } + /* Binary numeric promotion is performed on the operands */ + binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + /* The type of the relation expression is always BOOLEAN */ + prom_type = boolean_type_node; + break; + + /* 15.20 Equality Operator */ + case EQ_EXPR: + case NE_EXPR: + /* 15.20.1 Numerical Equality Operators == and != */ + /* Binary numeric promotion is performed on the operands */ + if (JPRIMITIVE_TYPE_P (op1_type) && JPRIMITIVE_TYPE_P (op2_type)) + binary_numeric_promotion (op1_type, op2_type, &op1, &op2); + + /* 15.20.2 Boolean Equality Operators == and != */ + else if (TREE_CODE (op1_type) == BOOLEAN_TYPE && + TREE_CODE (op2_type) == BOOLEAN_TYPE) + ; /* Nothing to do here */ + + /* 15.20.3 Reference Equality Operators == and != */ + /* Types have to be either references or the null type */ + else if ((op1 == null_pointer_node || op2 == null_pointer_node + || JREFERENCE_TYPE_P (op1_type) + || JREFERENCE_TYPE_P (op2_type)) + && ((op1_type == op2_type) + /* The should use a can_cast_to_p() */ + )) + ; /* Nothing to do here */ + + /* Else we have an error figure what can't be converted into + what and report the error */ + else + { + char *t1; + t1 = strdup ((char *)lang_printable_name (op1_type)); + parse_error_context + (wfl_operator, "Incompatible type for `%s'. Can't convert `%s' " + "to `%s'", operator_string (node), t1, + lang_printable_name (op2_type)); + free (t1); + TREE_TYPE (node) = boolean_type_node; + error_found = 1; + break; + } + prom_type = boolean_type_node; + break; + } + + /* Then check the initialization of the RHS. We don't do that if + we're dealing with a node that is part of a compound + assignment. We then silence further error message if the variable + wasn't initialized */ + if (not_initialized_as_it_should_p (op2) && !COMPOUND_ASSIGN_P (node)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_op2, DECL_NAME (op2)); + INITIALIZED_P (op2) = 1; + } + + if (error_found) + return error_mark_node; + + TREE_OPERAND (node, 0) = op1; + TREE_OPERAND (node, 1) = op2; + TREE_TYPE (node) = prom_type; + return fold (node); +} + +/* Build an incomplete unary operator expression. Unary `+' node is + build as a CONV_EXPR, even though its tree code is overridden by a + JAVA_UNARY_PLUS_EXPR that isn't a tree code, to differentiate it during + the walk. */ + +static tree +build_unaryop (op_token, op_location, op1) + int op_token, op_location; + tree op1; +{ + enum tree_code op; + tree unaryop; + switch (op_token) + { + case PLUS_TK: op = CONVERT_EXPR; break; + case MINUS_TK: op = NEGATE_EXPR; break; + case NEG_TK: op = TRUTH_NOT_EXPR; break; + case NOT_TK: op = BIT_NOT_EXPR; break; + default: fatal ("Unknown token `%d' for unary operator - build_unaryop", + op_token); + } + + unaryop = build1 (op, NULL_TREE, op1); + if (op_token == PLUS_TK) + TREE_SET_CODE (unaryop, JAVA_UNARY_PLUS_EXPR); + + TREE_SIDE_EFFECTS (unaryop) = 1; + /* Store the location of the operator, for better error report. The + string of the operator will be rebuild based on the OP value. */ + EXPR_WFL_LINECOL (unaryop) = op_location; + return unaryop; +} + +/* Special case for the ++/-- operators, since they require an extra + argument to build, which is set to NULL and patched + later. IS_POST_P is 1 if the operator, 0 otherwise. */ + +static tree +build_incdec (op_token, op_location, op1, is_post_p) + int op_token, op_location; + tree op1; + int is_post_p; +{ + static enum tree_code lookup [2][2] = + { + { PREDECREMENT_EXPR, PREINCREMENT_EXPR, }, + { POSTDECREMENT_EXPR, POSTINCREMENT_EXPR, }, + }; + tree node = build (lookup [is_post_p][(op_token - DECR_TK)], + NULL_TREE, op1, NULL_TREE); + TREE_SIDE_EFFECTS (node) = 1; + /* Store the location of the operator, for better error report. The + string of the operator will be rebuild based on the OP value. */ + EXPR_WFL_LINECOL (node) = op_location; + return node; +} + +/* Build an incomplete cast operator, based on the use of the + CONVERT_EXPR. Note that TREE_TYPE of the constructed node is + set. java_complete_tree is trained to walk a CONVERT_EXPR even + though its type is already set. */ + +static tree +build_cast (location, type, exp) + int location; + tree type, exp; +{ + tree node = build1 (CONVERT_EXPR, type, exp); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +/* 15.14 Unary operators. We return error_mark_node in case of error, + but preserve the type of NODE if the type is fixed. */ + +static tree +patch_unaryop (node, wfl_op) + tree node; + tree wfl_op; +{ + tree op = TREE_OPERAND (node, 0); + tree op_type = TREE_TYPE (op); + tree prom_type, value; + int code = TREE_CODE (node); + int error_found = 0; + + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + switch (code) + { + /* 15.13.2 Postfix Increment Operator ++ */ + case POSTINCREMENT_EXPR: + /* 15.13.3 Postfix Increment Operator -- */ + case POSTDECREMENT_EXPR: + /* 15.14.1 Prefix Increment Operator ++ */ + case PREINCREMENT_EXPR: + /* 15.14.2 Prefix Decrement Operator -- */ + case PREDECREMENT_EXPR: + if (!DECL_P (op)) + { + parse_error_context (wfl_operator, "Invalid argument to `%s'", + operator_string (node)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + else if (FIELD_FINAL (op)) + { + parse_error_context + (wfl_op, "Can't assign a value to the final variable `%s'", + IDENTIFIER_POINTER (EXPR_WFL_NODE (wfl_op))); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + /* From now on, we know that op if a variable and that it has a + valid wfl. We use wfl_op to locate errors related to the + ++/-- operand. */ + else if (!JNUMERIC_TYPE_P (op_type)) + { + parse_error_context + (wfl_op, "Invalid argument type `%s' to `%s'", + lang_printable_name (op_type), operator_string (node)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + else + { + /* Before the addition, binary numeric promotion if performed on + both operands */ + value = integer_one_node; + prom_type = binary_numeric_promotion (op_type, TREE_TYPE (value), + &op, &value); + /* And write the promoted increment back */ + TREE_OPERAND (node, 1) = value; + } + break; + + /* 15.14.3 Unary Plus Operator + */ + case JAVA_UNARY_PLUS_EXPR: + /* 15.14.4 Unary Minus Operator - */ + case NEGATE_EXPR: + if (!JNUMERIC_TYPE_P (op_type)) + { + ERROR_CANT_CONVERT_TO_NUMERIC (wfl_operator, node, op_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + /* Unary numeric promotion is performed on operand */ + else + { + prom_type = promote_type (op_type); + op = convert (prom_type, op); + if (code == JAVA_UNARY_PLUS_EXPR) + node = op; + } + break; + + /* 15.14.5 Bitwise Complement Operator ~ */ + case BIT_NOT_EXPR: + if (!JINTEGRAL_TYPE_P (op_type)) + { + ERROR_CAST_NEEDED_TO_INTEGRAL (wfl_operator, node, op_type); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + else + { + prom_type = promote_type (op_type); + op = convert (prom_type, op); + } + break; + + /* 15.14.6 Logical Complement Operator ! */ + case TRUTH_NOT_EXPR: + if (TREE_CODE (op_type) != BOOLEAN_TYPE) + { + ERROR_CANT_CONVERT_TO_BOOLEAN (wfl_operator, node, op_type); + TREE_TYPE (node) = boolean_type_node; + error_found = 1; + } + else + prom_type = boolean_type_node; + break; + + /* 15.15 Cast Expression */ + case CONVERT_EXPR: + value = patch_cast (node, wfl_op, wfl_operator); + if (value == error_mark_node) + { + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + else + node = value; + break; + } + + /* Check variable initialization */ + if (not_initialized_as_it_should_p (op)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_op, DECL_NAME (op)); + INITIALIZED_P (op) = 1; + } + + if (error_found) + return error_mark_node; + /* In the case of JAVA_UNARY_PLUS_EXPR, we replaced NODE by a new one */ + else if (code != JAVA_UNARY_PLUS_EXPR && code != CONVERT_EXPR) + { + TREE_OPERAND (node, 0) = op; + TREE_TYPE (node) = prom_type; + } + return fold (node); +} + +/* Generic type resolution that sometimes takes place during node + patching. Returned the resolved type or generate an error + message. Return the resolved type or NULL_TREE. */ + +static tree +resolve_type_during_patch (type) + tree type; +{ + if (unresolved_type_p (type, NULL)) + { + tree type_decl = resolve_no_layout (EXPR_WFL_NODE (type), NULL_TREE); + if (!type_decl) + { + parse_error_context (type, + "Class `%s' not found in type declaration", + IDENTIFIER_POINTER (EXPR_WFL_NODE (type))); + return NULL_TREE; + } + else + return TREE_TYPE (type_decl); + } + return type; +} +/* 5.5 Casting Conversion. error_mark_node is returned if an error is + found. Otherwise NODE or something meant to replace it is returned. */ + +static tree +patch_cast (node, wfl_op, wfl_operator) + tree node; + tree wfl_op; + tree wfl_operator; +{ + tree op = TREE_OPERAND (node, 0); + tree op_type = TREE_TYPE (op); + tree cast_type = TREE_TYPE (node); + char *t1; + + /* First resolve OP_TYPE if unresolved */ + if (!(cast_type = resolve_type_during_patch (cast_type))) + return error_mark_node; + + /* Check on cast that are proven correct at compile time */ + if (JNUMERIC_TYPE_P (cast_type) && JNUMERIC_TYPE_P (op_type)) + { + static tree convert_narrow (); + /* Same type */ + if (cast_type == op_type) + return node; + + /* Try widening/narowwing convertion. Potentially, things need + to be worked out in gcc so we implement the extreme cases + correctly. fold_convert() needs to be fixed. */ + return convert (cast_type, op); + } + + /* The remaining legal casts involve conversion between reference + types. Check for their compile time correctness. */ + if (JREFERENCE_TYPE_P (op_type) && JREFERENCE_TYPE_P (cast_type) + && valid_ref_assignconv_cast_p (op_type, cast_type, 1)) + { + TREE_TYPE (node) = promote_type (cast_type); + /* Now, the case can be determined correct at compile time if + OP_TYPE can be converted into CAST_TYPE by assignment + conversion (5.2) */ + + if (valid_ref_assignconv_cast_p (op_type, cast_type, 0)) + return node; + + /* The cast requires a run-time check */ + return build (CALL_EXPR, promote_type (cast_type), + build_address_of (soft_checkcast_node), + tree_cons (NULL_TREE, build_class_ref (cast_type), + build_tree_list (NULL_TREE, op)), + NULL_TREE); + } + + /* Any other casts are proven incorrect at compile time */ + t1 = strdup ((char *)lang_printable_name (op_type)); + parse_error_context (wfl_operator, "Invalid cast from `%s' to `%s'", + t1, lang_printable_name (cast_type)); + free (t1); + return error_mark_node; +} + +/* Build an ARRAY_REF incomplete tree node. Note that operand 1 isn't + a list of indices. */ +static tree +build_array_ref (location, array, index) + int location; + tree array, index; +{ + tree node = build (ARRAY_REF, NULL_TREE, array, index); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +/* 15.12 Array Access Expression */ + +static tree +patch_array_ref (node, wfl_array, wfl_index) + tree node, wfl_array, wfl_index; +{ + tree array = TREE_OPERAND (node, 0); + tree array_type = TREE_TYPE (array); + tree index = TREE_OPERAND (node, 1); + tree index_type = TREE_TYPE (index); + tree promoted_index_type; + int error_found = 0; + + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + if (not_initialized_as_it_should_p (array)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_array, DECL_NAME (array)); + INITIALIZED_P (array) = 1; + } + if (! flag_emit_class_files) + array = save_expr (array); + + if (TREE_CODE (array_type) == POINTER_TYPE) + array_type = TREE_TYPE (array_type); + + /* The array reference must be an array */ + if (!TYPE_ARRAY_P (array_type)) + { + parse_error_context + (wfl_operator, "`[]' can only be applied to arrays. It can't be " + "applied to `%s'", lang_printable_name (array_type)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + + /* The array index underdoes unary numeric promotion. The promoted + type must be int */ + promoted_index_type = promote_type (index_type); + if (promoted_index_type != int_type_node) + { + int could_cast = can_cast_to_p (index_type, int_type_node); + parse_error_context + (wfl_operator, + (could_cast ? "Incompatible type for `[]'. Explicit cast needed to " + "convert `%s' to `int'" : "Incompatible type for `[]'. " + "Can't convert `%s' to `int'"), + lang_printable_name (index_type)); + TREE_TYPE (node) = error_mark_node; + error_found = 1; + } + + /* Now if the index is a var/parm decl, check on its initialization */ + if (not_initialized_as_it_should_p (index)) + { + ERROR_VARIABLE_NOT_INITIALIZED (wfl_index, DECL_NAME (index)); + INITIALIZED_P (index) = 1; + } + + if (error_found) + return error_mark_node; + index = convert (promoted_index_type, index); + + if (TREE_CODE (array_type) == RECORD_TYPE) + array_type = promote_type (TYPE_ARRAY_ELEMENT (array_type)); + if (flag_emit_class_files) + { + TREE_OPERAND (node, 0)= array; + TREE_OPERAND (node, 1)= index; + } + else + node = build_java_arrayaccess (array, array_type, index); + TREE_TYPE (node) = array_type; + return node; +} + +/* 15.9 Array Creation Expressions */ + +static tree +build_newarray_node (type, dims, extra_dims) + tree type; + tree dims; + int extra_dims; +{ + tree node = + build (CALL_EXPR, NULL_TREE, type, nreverse (dims), + build_int_2 (extra_dims, 0)); + TREE_SET_CODE (node, JAVA_NEW_ARRAY_EXPR); + return node; +} + +static tree +patch_newarray (node) + tree node; +{ + tree type = TREE_OPERAND (node, 0); + tree dims = TREE_OPERAND (node, 1); + tree cdim, array_type; + int error_found = 0; + int ndims = 0; + int xdims = TREE_INT_CST_LOW (TREE_OPERAND (node, 2)); + int total_dims; + + /* Dimension types are verified. It's better for the types to be + verified in order. */ + for (cdim = dims, ndims = 0; cdim; cdim = TREE_CHAIN (cdim), ndims++ ) + { + int dim_error = 0; + tree dim = TREE_VALUE (cdim); + + /* Dim might have been saved during its evaluation */ + dim = (TREE_CODE (dim) == SAVE_EXPR ? dim = TREE_OPERAND (dim, 0) : dim); + + /* The type of each specified dimension must be an integral type. */ + if (!JINTEGRAL_TYPE_P (TREE_TYPE (dim))) + dim_error = 1; + + /* Each expression undergoes an unary numeric promotion (5.6.1) and the + promoted type must be int. */ + else + { + dim = convert (promote_type (TREE_TYPE (dim)), dim); + if (TREE_TYPE (dim) != int_type_node) + dim_error = 1; + } + + /* Report errors on types here */ + if (dim_error) + { + parse_error_context + (TREE_PURPOSE (cdim), + "Incompatible type for dimension in array creation expression. " + "%s convert `%s' to `int'", + (can_cast_to_p (TREE_TYPE (dim), int_type_node) ? + "Explicit cast needed to" : "Can't"), + lang_printable_name (TREE_TYPE (dim))); + error_found = 1; + } + + /* Check for uninitialized variables */ + if (not_initialized_as_it_should_p (dim)) + { + ERROR_VARIABLE_NOT_INITIALIZED (TREE_PURPOSE (cdim), + DECL_NAME (dim)); + INITIALIZED_P (dim) = 1; + error_found = 1; + } + + TREE_PURPOSE (cdim) = NULL_TREE; + } + + /* Resolve array base type if unresolved */ + if (!(type = resolve_type_during_patch (type))) + error_found = 1; + + if (error_found) + { + /* We don't want further evaluation of this bogus array creation + operation */ + TREE_TYPE (node) = error_mark_node; + return error_mark_node; + } + + /* The node is transformed into a function call. Things are done + differently according to the number of dimensions. If the number + of dimension is equal to 1, then the nature of the base type + (primitive or not) matters. */ + total_dims = xdims + ndims; + if (total_dims == 1) + { + if (JPRIMITIVE_TYPE_P (type)) + { + int type_code; + if (type == boolean_type_node) + type_code = 4; + else if (type == char_type_node) + type_code = 5; + else if (type == float_type_node) + type_code = 6; + else if (type == double_type_node) + type_code = 7; + else if (type == byte_type_node) + type_code = 8; + else if (type == short_type_node) + type_code = 9; + else if (type == int_type_node) + type_code = 10; + else if (type == long_type_node) + type_code = 11; + else + fatal ("Can't compute type code - patch_newarray"); + return build_newarray (type_code, TREE_VALUE (dims)); + } + else + return build_anewarray (type, TREE_VALUE (dims)); + } + + /* Add extra dimensions as unknown dimensions */ + while (xdims--) + dims = + chainon (dims, build_tree_list (NULL_TREE, integer_negative_one_node)); + dims = chainon (dims, build_tree_list (NULL_TREE, integer_zero_node)); + + /* Can't reuse what's already written in expr.c because it uses the + JVM stack representation. Provide a build_multianewarray. FIXME */ + array_type = type; + for (cdim = TREE_CHAIN (dims); cdim; cdim = TREE_CHAIN (cdim)) + array_type = build_java_array_type (promote_type (array_type), + TREE_CODE (cdim) == INTEGER_CST ? + TREE_INT_CST_LOW (cdim) : -1); + return build (CALL_EXPR, + promote_type (array_type), + build_address_of (soft_multianewarray_node), + tree_cons (NULL_TREE, build_class_ref (array_type), + tree_cons (NULL_TREE, + build_int_2 (total_dims, 0), dims )), + NULL_TREE); +} + +static tree +build_this (location) + int location; +{ + tree node = build_wfl_node (this_identifier_node, input_filename, 0, 0); + TREE_SET_CODE (node, JAVA_THIS_EXPR); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +/* 14.15 The return statement. It builds a modify expression that + assigns the returned value to the RESULT_DECL that hold the value + to be returned. */ + +static tree +build_return (location, op) + int location; + tree op; +{ + tree node = build1 (RETURN_EXPR, NULL_TREE, op); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +static tree +patch_return (node) + tree node; +{ + tree return_exp = TREE_OPERAND (node, 0); + tree meth = current_function_decl; + tree mtype = TREE_TYPE (TREE_TYPE (current_function_decl)); + tree modify; + int error_found = 0; + + TREE_TYPE (node) = error_mark_node; + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* It's invalid to have a return value within a function that is + declared with the keyword void or that is a constructor */ + if (return_exp && (mtype == void_type_node || DECL_CONSTRUCTOR_P (meth))) + error_found = 1; + + /* It's invalid to have a no return value within a function that + isn't declared with the keyword `void' */ + if (!return_exp && (mtype != void_type_node && !DECL_CONSTRUCTOR_P (meth))) + error_found = 2; + + if (error_found) + { + char *t = strdup ((char *)lang_printable_name (mtype)); + parse_error_context (wfl_operator, "`return' with%s value from `%s %s'", + (error_found == 1 ? "" : "out"), t, + lang_printable_name (meth)); + free (t); + return error_mark_node; + } + + /* If we have a return_exp, build a modify expression and expand it */ + if (return_exp) + { + modify = build (MODIFY_EXPR, NULL_TREE, DECL_RESULT (meth), return_exp); + EXPR_WFL_LINECOL (modify) = EXPR_WFL_LINECOL (node); + modify = java_complete_tree (modify); + if (modify != error_mark_node) + { + TREE_SIDE_EFFECTS (modify) = 1; + TREE_OPERAND (node, 0) = modify; + } + else + return error_mark_node; + } + TREE_TYPE (node) = void_type_node; + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* 14.8 The if Statement */ + +static tree +build_if_else_statement (location, expression, if_body, else_body) + int location; + tree expression, if_body, else_body; +{ + tree node; + /* FIXME: make else body be a void node, where this function is + called */ + if (!else_body) + else_body = build (COMPOUND_EXPR, void_type_node, NULL_TREE, NULL_TREE); + node = build (COND_EXPR, NULL_TREE, expression, if_body, else_body); + EXPR_WFL_LINECOL (node) = location; + return node; +} + +static tree +patch_if_else_statement (node) + tree node; +{ + tree expression = TREE_OPERAND (node, 0); + + TREE_TYPE (node) = error_mark_node; + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* The type of expression must be boolean */ + if (TREE_TYPE (expression) != boolean_type_node) + { + parse_error_context + (wfl_operator, + "Incompatible type for `if'. Can't convert `%s' to `boolean'", + lang_printable_name (TREE_TYPE (expression))); + return error_mark_node; + } + + TREE_TYPE (node) = void_type_node; + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* 14.6 Labeled Statements */ + +/* Action taken when a lableled statement is parsed. a new + LABELED_BLOCK_EXPR is created. No statement is attached to the + label, yet. */ + +static tree +build_labeled_block (location, label, wfl) + int location; + tree label, wfl; +{ + tree label_name = merge_qualified_name (label_id, label); + tree label_decl, node; + + /* Issue a warning if we try to reuse a label that was previously + declared */ + if (IDENTIFIER_LOCAL_VALUE (label_name)) + { + EXPR_WFL_LINECOL (wfl_operator) = location; + parse_warning_context (wfl_operator, "Declaration of `%s' shadows " + "a previous declaration", + IDENTIFIER_POINTER (label)); + EXPR_WFL_LINECOL (wfl_operator) = + EXPR_WFL_LINECOL (IDENTIFIER_LOCAL_VALUE (label_name)); + parse_warning_context (wfl_operator, "This is the location of the " + "previous declaration of label `%s'", + IDENTIFIER_POINTER (label)); + java_warning_count--; + } + + label_decl = create_label_decl (label_name); + node = build (LABELED_BLOCK_EXPR, NULL_TREE, label_decl, NULL_TREE); + EXPR_WFL_LINECOL (node) = location; + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* Generate a label crafting a unique name for it. This is used to + implicitely label loops that aren't the body part of labeled + statement. */ + +static tree +generate_labeled_block () +{ + static int l_number = 0; + char buf [20]; + tree label_name; + + sprintf (buf, "$a%d", l_number++); + return build_labeled_block (0, get_identifier (buf), NULL_TREE); +} + +/* A labeled statement LBE is attached a statement. If the statement + happens to be a loop, a link from the loop back to the label is + installed. */ + +static tree +complete_labeled_statement (lbe, statement) + tree lbe; /* Labeled block expr */ + tree statement; +{ + /* In anyways, tie the loop to its statement */ + LABELED_BLOCK_BODY (lbe) = statement; + + /* Ok, if statement is a for loop, we have to attach the labeled + statement to the block the for loop belongs to and return the + block instead */ + if (TREE_CODE (statement) == LOOP_EXPR && IS_FOR_LOOP_P (statement)) + { + java_method_add_stmt (current_function_decl, lbe); + return exit_block (); + } + + return lbe; +} + +/* 14.10, 14.11, 14.12 Loop Statements */ + +/* Create an empty LOOP_EXPR and make it the last in the nested loop + list. */ + +static tree +build_new_loop (loop_body) + tree loop_body; +{ + tree loop = build (LOOP_EXPR, NULL_TREE, loop_body); + TREE_SIDE_EFFECTS (loop) = 1; + PUSH_LOOP (loop); + return loop; +} + +/* Create a loop body according to the following structure: + COMPOUND_EXPR + COMPOUND_EXPR (loop main body) + EXIT_EXPR (this order is for while/for loops. + LABELED_BLOCK_EXPR the order is reversed for do loops) + LABEL_DECL (continue occurding here branche at the + BODY end of this labeled block) + INCREMENT (if any) + + REVERSED, if non zero, tells that the loop condition expr comes + after the body, like in the do-while loop. */ + +static tree +build_loop_body (location, condition, reversed) + int location; + tree condition; + int reversed; +{ + tree first, second, label, body; + + condition = build (EXIT_EXPR, NULL_TREE, condition); /* Force walk */ + EXPR_WFL_LINECOL (condition) = location; /* For accurate error report */ + condition = build_debugable_stmt (location, condition); + TREE_SIDE_EFFECTS (condition) = 1; + + body = generate_labeled_block (); + first = (reversed ? body : condition); + second = (reversed ? condition : body); + return + build (COMPOUND_EXPR, NULL_TREE, + build (COMPOUND_EXPR, NULL_TREE, first, second), size_zero_node); +} + +/* Install CONDITION (if any) and loop BODY (using REVERSED to tell + their order) on the current loop. Unlink the current loop from the + loop list. */ + +static tree +complete_loop_body (location, condition, body, reversed) + int location; + tree condition, body; + int reversed; +{ + tree to_return = ctxp->current_loop; + tree loop_body = LOOP_EXPR_BODY (to_return); + if (condition) + { + tree cnode = LOOP_EXPR_BODY_CONDITION_EXPR (loop_body, reversed); + /* We wrapped the EXIT_EXPR around a WFL so we can debug it. + The real EXIT_EXPR is one operand further. */ + EXPR_WFL_LINECOL (cnode) = location; + /* This one is for accurate error reports */ + EXPR_WFL_LINECOL (TREE_OPERAND (cnode, 0)) = location; + TREE_OPERAND (TREE_OPERAND (cnode, 0), 0) = condition; + } + LOOP_EXPR_BODY_BODY_EXPR (loop_body, reversed) = body; + POP_LOOP (); + return to_return; +} + +/* Tailored version of complete_loop_body for FOR loops, when FOR + loops feature the condition part */ + +static tree +complete_for_loop (location, condition, update, body) + int location; + tree condition, update, body; +{ + /* Put the condition and the loop body in place */ + tree loop = complete_loop_body (location, condition, body, 0); + /* LOOP is the current loop which has been now popped of the loop + stack. Install the update block */ + LOOP_EXPR_BODY_UPDATE_BLOCK (LOOP_EXPR_BODY (loop)) = update; + return loop; +} + +/* If the loop isn't surrounded by a labeled statement, create one and + insert LOOP as it's body. */ + +static tree +patch_loop_statement (loop) + tree loop; +{ + tree cbl, loop_label, to_return_as_loop; + + if (LOOP_HAS_LABEL_P (loop)) + { + loop_label = ctxp->current_labeled_block; + to_return_as_loop = loop; + } + else + { + loop_label = generate_labeled_block (); + LABELED_BLOCK_BODY (loop_label) = loop; + PUSH_LABELED_BLOCK (loop_label); + to_return_as_loop = loop_label; + } + TREE_TYPE (to_return_as_loop) = void_type_node; + return to_return_as_loop; +} + +/* 14.13, 14.14: break and continue Statements */ + +/* Build a break or a continue statement. a null NAME indicates an + unlabeled break/continue statement. */ + +static tree +build_bc_statement (location, is_break, name) + int location, is_break; + tree name; +{ + tree break_continue, label_block_expr = NULL_TREE; + + if (name) + { + if (!(label_block_expr = IDENTIFIER_LOCAL_VALUE + (merge_qualified_name (label_id, EXPR_WFL_NODE (name))))) + /* Null means that we don't have a target for this named + break/continue. In this case, we make the target to be the + label name, so that the error can be reported accuratly in + patch_bc_statement. */ + label_block_expr = EXPR_WFL_NODE (name); + } + /* Unlabeled break/continue will be handled during the + break/continue patch operation */ + break_continue + = build (EXIT_BLOCK_EXPR, NULL_TREE, label_block_expr, NULL_TREE); + + IS_BREAK_STMT_P (break_continue) = is_break; + TREE_SIDE_EFFECTS (break_continue) = 1; + EXPR_WFL_LINECOL (break_continue) = location; + return break_continue; +} + +/* Verification of a break/continue statement. */ + +static tree +patch_bc_statement (node) + tree node; +{ + tree bc_label = EXIT_BLOCK_LABELED_BLOCK (node), target_stmt; + int is_unlabeled = 0; + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* Not having a target means that the break/continue statement is + unlabeled. We try to find a descent label for it */ + if (!bc_label) + { + is_unlabeled = 1; + /* There should be a loop to branch to */ + if (ctxp->current_loop) + { + /* At that stage, we're in the loop body, which is + encapsulated around a LABELED_BLOCK_EXPR. So searching + the current loop label requires us to consider the + labeled block before the current one. */ + if (!LOOP_HAS_LABEL_SKIP_P (ctxp->current_loop)) + fatal ("unlabeled loop has not installed label -- " + "patch_bc_statement"); + bc_label = TREE_CHAIN (ctxp->current_labeled_block); + } + /* Not having a loop to break/continue to is an error */ + else + { + parse_error_context (wfl_operator, "`%s' must be in loop%s", + (IS_BREAK_STMT_P (node) ? "break" : "continue"), + (IS_BREAK_STMT_P (node) ? " or switch" : "")); + return error_mark_node; + } + } + /* Having an identifier here means that the target is unknown. */ + else if (TREE_CODE (bc_label) == IDENTIFIER_NODE) + { + parse_error_context (wfl_operator, "No label definition found for `%s'", + IDENTIFIER_POINTER (bc_label)); + return error_mark_node; + } + + /* Find the statement we're targeting. */ + target_stmt = LABELED_BLOCK_BODY (bc_label); + + /* 14.13 The break Statement */ + if (IS_BREAK_STMT_P (node)) + { + /* Named break are always fine, as far as they have a target + (already verified). Anonymous break need to target + while/do/for/switch */ + if (is_unlabeled && + !(TREE_CODE (target_stmt) == LOOP_EXPR /* do/while/for */ + || 0)) /* switch FIXME */ + { + parse_error_context (wfl_operator, + "`break' must be in loop or switch"); + return error_mark_node; + } + /* If previously unlabeled, install the new found label */ + if (is_unlabeled) + EXIT_BLOCK_LABELED_BLOCK (node) = bc_label; + } + /* 14.14 The continue Statement */ + /* The continue statement must always target a loop */ + else + { + if (TREE_CODE (target_stmt) != LOOP_EXPR) /* do/while/for */ + { + parse_error_context (wfl_operator, "`continue' must be in loop"); + return error_mark_node; + } + /* Everything looks good. We can fix the `continue' jump to go + at the place in the loop were the continue is. The continue + is the current labeled block, by construction. */ + EXIT_BLOCK_LABELED_BLOCK (node) = ctxp->current_labeled_block; + } + + /* Our break/continue don't return values. */ + TREE_TYPE (node) = void_type_node; + /* Encapsulate the break within a compound statement so that it's + expanded all the times by expand_expr (and not clobered + sometimes, like after a if statement) */ + node = add_stmt_to_compound (NULL_TREE, void_type_node, node); + TREE_SIDE_EFFECTS (node) = 1; + return node; +} + +/* Process the exit expression belonging to a loop. Its type must be + boolean. */ + +static tree +patch_exit_expr (node) + tree node; +{ + tree expression = TREE_OPERAND (node, 0); + TREE_TYPE (node) = error_mark_node; + EXPR_WFL_LINECOL (wfl_operator) = EXPR_WFL_LINECOL (node); + + /* The type of expression must be boolean */ + if (TREE_TYPE (expression) != boolean_type_node) + { + parse_error_context + (wfl_operator, + "Incompatible type for loop conditional. Can't convert `%s' to " + "`boolean'", + lang_printable_name (TREE_TYPE (expression))); + return error_mark_node; + } + /* Now we know things are allright, invert the condition, fold and + return */ + TREE_OPERAND (node, 0) = + fold (build1 (TRUTH_NOT_EXPR, boolean_type_node, expression)); + TREE_TYPE (node) = void_type_node; + return node; +} diff --git a/gcc/java/typeck.c b/gcc/java/typeck.c new file mode 100644 index 00000000000..211e4b69cc4 --- /dev/null +++ b/gcc/java/typeck.c @@ -0,0 +1,785 @@ +/* Handle types for the GNU compiler for the Java(TM) language. + Copyright (C) 1996 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +/* Written by Per Bothner */ + +#include "config.h" +#include "tree.h" +#include "obstack.h" +#include "java-tree.h" +#include "jcf.h" +#include "convert.h" + +tree * type_map; +extern struct obstack permanent_obstack; + +/* Set the type of the local variable with index SLOT to TYPE. */ + +void +set_local_type (slot, type) + int slot; + tree type; +{ + int max_locals = DECL_MAX_LOCALS(current_function_decl); + int nslots = TYPE_IS_WIDE (type) ? 2 : 1; + if (slot < 0 || slot + nslots - 1 >= max_locals) + fatal ("invalid local variable index"); + type_map[slot] = type; + while (--nslots > 0) + type_map[++slot] = void_type_node; +} + +extern tree convert_to_integer (tree type, tree expr); +extern tree convert_to_real (tree type, tree expr); +extern tree convert_to_pointer (tree type, tree expr); + +/* Create an expression whose value is that of EXPR, + converted to type TYPE. The TREE_TYPE of the value + is always TYPE. This function implements all reasonable + conversions; callers should filter out those that are + not permitted by the language being compiled. */ + +tree +convert (type, expr) + tree type, expr; +{ + register enum tree_code code = TREE_CODE (type); + + if (type == TREE_TYPE (expr) + || TREE_CODE (expr) == ERROR_MARK) + return expr; + if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) + return error_mark_node; + if (code == BOOLEAN_TYPE) + return fold (convert_to_boolean (type, expr)); + if (code == INTEGER_TYPE) + return fold (convert_to_integer (type, expr)); + if (code == REAL_TYPE) + return fold (convert_to_real (type, expr)); + if (code == CHAR_TYPE) + return fold (convert_to_char (type, expr)); + if (code == POINTER_TYPE) + return fold (convert_to_pointer (type, expr)); + error ("conversion to non-scalar type requested"); + return error_mark_node; +} + +tree +convert_to_char (type, expr) + tree type, expr; +{ + return build1 (NOP_EXPR, type, expr); +} + +tree +convert_to_boolean (type, expr) + tree type, expr; +{ + return build1 (NOP_EXPR, type, expr); +} + +/* Print an error message for invalid use of an incomplete type. + VALUE is the expression that was used (or 0 if that isn't known) + and TYPE is the type that was invalid. */ + +void +incomplete_type_error (value, type) + tree value; + tree type; +{ + error ("internal error - use of undefined type"); +} + +/* Return a data type that has machine mode MODE. + If the mode is an integer, + then UNSIGNEDP selects between signed and unsigned types. */ + +tree +type_for_mode (mode, unsignedp) + enum machine_mode mode; + int unsignedp; +{ + if (mode == TYPE_MODE (int_type_node)) + return unsignedp ? unsigned_int_type_node : int_type_node; + if (mode == TYPE_MODE (long_type_node)) + return unsignedp ? unsigned_long_type_node : long_type_node; + if (mode == TYPE_MODE (short_type_node)) + return unsignedp ? unsigned_short_type_node : short_type_node; + if (mode == TYPE_MODE (byte_type_node)) + return unsignedp ? unsigned_byte_type_node : byte_type_node; + if (mode == TYPE_MODE (float_type_node)) + return float_type_node; + if (mode == TYPE_MODE (double_type_node)) + return double_type_node; + +#if 0 + if (mode == TYPE_MODE (build_pointer_type (char_type_node))) + return build_pointer_type (char_type_node); + + if (mode == TYPE_MODE (build_pointer_type (integer_type_node))) + return build_pointer_type (integer_type_node); +#endif + + return 0; +} + +/* Return an integer type with BITS bits of precision, + that is unsigned if UNSIGNEDP is nonzero, otherwise signed. */ + +tree +type_for_size (bits, unsignedp) + unsigned bits; + int unsignedp; +{ + if (bits <= TYPE_PRECISION (byte_type_node)) + return unsignedp ? unsigned_byte_type_node : byte_type_node; + if (bits <= TYPE_PRECISION (short_type_node)) + return unsignedp ? unsigned_short_type_node : short_type_node; + if (bits <= TYPE_PRECISION (int_type_node)) + return unsignedp ? unsigned_int_type_node : int_type_node; + if (bits <= TYPE_PRECISION (long_type_node)) + return unsignedp ? unsigned_long_type_node : long_type_node; + return 0; +} + +/* Return a type the same as TYPE except unsigned or + signed according to UNSIGNEDP. */ + +tree +signed_or_unsigned_type (unsignedp, type) + int unsignedp; + tree type; +{ + if (! INTEGRAL_TYPE_P (type)) + return type; + if (TYPE_PRECISION (type) == TYPE_PRECISION (int_type_node)) + return unsignedp ? unsigned_int_type_node : int_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (byte_type_node)) + return unsignedp ? unsigned_byte_type_node : byte_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (short_type_node)) + return unsignedp ? unsigned_short_type_node : short_type_node; + if (TYPE_PRECISION (type) == TYPE_PRECISION (long_type_node)) + return unsignedp ? unsigned_long_type_node : long_type_node; + return type; +} + +/* Return a signed type the same as TYPE in other respects. */ + +tree +signed_type (type) + tree type; +{ + return signed_or_unsigned_type (0, type); +} + +/* Return an unsigned type the same as TYPE in other respects. */ + +tree +unsigned_type (type) + tree type; +{ + return signed_or_unsigned_type (1, type); + +} + +/* Mark EXP saying that we need to be able to take the + address of it; it should not be allocated in a register. + Value is 1 if successful. */ + +int +mark_addressable (exp) + tree exp; +{ + register tree x = exp; + while (1) + switch (TREE_CODE (x)) + { + case ADDR_EXPR: + case COMPONENT_REF: + case ARRAY_REF: + case REALPART_EXPR: + case IMAGPART_EXPR: + x = TREE_OPERAND (x, 0); + break; + + case TRUTH_ANDIF_EXPR: + case TRUTH_ORIF_EXPR: + case COMPOUND_EXPR: + x = TREE_OPERAND (x, 1); + break; + + case COND_EXPR: + return mark_addressable (TREE_OPERAND (x, 1)) + & mark_addressable (TREE_OPERAND (x, 2)); + + case CONSTRUCTOR: + TREE_ADDRESSABLE (x) = 1; + return 1; + + case INDIRECT_REF: + /* We sometimes add a cast *(TYPE*)&FOO to handle type and mode + incompatibility problems. Handle this case by marking FOO. */ + if (TREE_CODE (TREE_OPERAND (x, 0)) == NOP_EXPR + && TREE_CODE (TREE_OPERAND (TREE_OPERAND (x, 0), 0)) == ADDR_EXPR) + { + x = TREE_OPERAND (TREE_OPERAND (x, 0), 0); + break; + } + if (TREE_CODE (TREE_OPERAND (x, 0)) == ADDR_EXPR) + { + x = TREE_OPERAND (x, 0); + break; + } + return 1; + + case VAR_DECL: + case CONST_DECL: + case PARM_DECL: + case RESULT_DECL: + case FUNCTION_DECL: + TREE_ADDRESSABLE (x) = 1; +#if 0 /* poplevel deals with this now. */ + if (DECL_CONTEXT (x) == 0) + TREE_ADDRESSABLE (DECL_ASSEMBLER_NAME (x)) = 1; +#endif + /* drops through */ + default: + return 1; + } +} + +/* Thorough checking of the arrayness of TYPE. */ + +int +is_array_type_p (type) + tree type; +{ + return TREE_CODE (type) == POINTER_TYPE + && TREE_CODE (TREE_TYPE (type)) == RECORD_TYPE + && TYPE_ARRAY_P (TREE_TYPE (type)); +} + +/* Return the length of a Java array type. + Return -1 if the length is unknown or non-constant. */ + +HOST_WIDE_INT +java_array_type_length (array_type) + tree array_type; +{ + tree arfld; + if (TREE_CODE (array_type) == POINTER_TYPE) + array_type = TREE_TYPE (array_type); + arfld = TREE_CHAIN (TREE_CHAIN (TYPE_FIELDS (array_type))); + if (arfld != NULL_TREE) + { + tree index_type = TYPE_DOMAIN (TREE_TYPE (arfld)); + tree high = TYPE_MAX_VALUE (index_type); + if (TREE_CODE (high) == INTEGER_CST) + return TREE_INT_CST_LOW (high) + 1; + } + return -1; +} + +tree +build_prim_array_type (element_type, length) + tree element_type; + HOST_WIDE_INT length; +{ + tree max_index = build_int_2 (length - 1, 0); + TREE_TYPE (max_index) = sizetype; + return build_array_type (element_type, build_index_type (max_index)); +} + +/* Return a Java array type with a given ELEMENT_TYPE and LENGTH. + These are hashed (shared) using IDENTIFIER_SIGNATURE_TYPE. + The LENGTH is -1 if the length is unknown. */ + +tree +build_java_array_type (element_type, length) + tree element_type; + HOST_WIDE_INT length; +{ + tree sig, t, fld; + char buf[12]; + tree elsig = build_java_signature (element_type); + tree el_name = element_type; + sprintf (buf, length >= 0 ? "[%d" : "[", length); + sig = ident_subst (IDENTIFIER_POINTER (elsig), IDENTIFIER_LENGTH (elsig), + buf, 0, 0, ""); + t = IDENTIFIER_SIGNATURE_TYPE (sig); + if (t != NULL_TREE) + return t; + t = make_class (); + IDENTIFIER_SIGNATURE_TYPE (sig) = t; + TYPE_ARRAY_P (t) = 1; + + if (TREE_CODE (el_name) == POINTER_TYPE) + el_name = TREE_TYPE (el_name); + el_name = TYPE_NAME (el_name); + if (TREE_CODE (el_name) == TYPE_DECL) + el_name = DECL_NAME (el_name); + TYPE_NAME (t) = identifier_subst (el_name, "", '.', '.', "[]"); + + set_java_signature (t, sig); + set_super_info (0, t, object_type_node, 0); + TYPE_ARRAY_ELEMENT (t) = element_type; + + /* Add length pseudo-field. */ + push_obstacks (&permanent_obstack, &permanent_obstack); + fld = build_decl (FIELD_DECL, get_identifier ("length"), int_type_node); + TYPE_FIELDS (t) = fld; + DECL_CONTEXT (fld) = t; + FIELD_PUBLIC (fld) = 1; + FIELD_FINAL (fld) = 1; + + if (length >= 0) + { + tree atype = build_prim_array_type (element_type, length); + tree arfld = build_decl (FIELD_DECL, get_identifier ("data"), atype); + DECL_CONTEXT (arfld) = t; + TREE_CHAIN (fld) = arfld; + } + else + TYPE_ALIGN (t) = TYPE_ALIGN (element_type); + pop_obstacks (); + + layout_class (t); + return t; +} + +/* Promote TYPE to the type actually used for fields and parameters. */ + +tree +promote_type (type) + tree type; +{ + switch (TREE_CODE (type)) + { + case RECORD_TYPE: + return build_pointer_type (CLASS_TO_HANDLE_TYPE (type)); + case BOOLEAN_TYPE: + if (type == boolean_type_node) + return promoted_boolean_type_node; + goto handle_int; + case CHAR_TYPE: + if (type == char_type_node) + return promoted_char_type_node; + goto handle_int; + case INTEGER_TYPE: + handle_int: + if (TYPE_PRECISION (type) < TYPE_PRECISION (int_type_node)) + { + if (type == short_type_node) + return promoted_short_type_node; + if (type == byte_type_node) + return promoted_byte_type_node; + return int_type_node; + } + /* ... else fall through ... */ + default: + return type; + } +} + +/* Parse a signature string, starting at *PTR and ending at LIMIT. + Return the seen TREE_TYPE, updating *PTR. */ + +static tree +parse_signature_type (ptr, limit) + const unsigned char **ptr, *limit; +{ + if ((*ptr) >= limit) + fatal ("bad signature string"); + switch (*(*ptr)) + { + case 'B': (*ptr)++; return byte_type_node; + case 'C': (*ptr)++; return char_type_node; + case 'D': (*ptr)++; return double_type_node; + case 'F': (*ptr)++; return float_type_node; + case 'S': (*ptr)++; return short_type_node; + case 'I': (*ptr)++; return int_type_node; + case 'J': (*ptr)++; return long_type_node; + case 'Z': (*ptr)++; return boolean_type_node; + case 'V': (*ptr)++; return void_type_node; + case '[': + for ((*ptr)++; (*ptr) < limit && isdigit (**ptr); ) (*ptr)++; + { + tree element_type = parse_signature_type (ptr, limit); + if (TREE_CODE (element_type) == RECORD_TYPE) + element_type = promote_type (element_type); + return build_java_array_type (element_type, -1); + } + case 'L': + { + const unsigned char *start = ++(*ptr); + register const unsigned char *str = start; + for ( ; ; str++) + { + if (str >= limit) + fatal ("bad signature string"); + if (*str == ';') + break; + } + *ptr = str+1; + return lookup_class (unmangle_classname (start, str - start)); + } + default: + fatal ("unrecognized signature string"); + } +} + +/* Parse a Java "mangled" signature string, starting at SIG_STRING, + and SIG_LENGTH bytes long. + Return a gcc type node. */ + +tree +parse_signature_string (sig_string, sig_length) + const unsigned char *sig_string; + int sig_length; +{ + tree result_type; + const unsigned char *str = sig_string; + const unsigned char *limit = str + sig_length; + + push_obstacks (&permanent_obstack, &permanent_obstack); + if (str < limit && str[0] == '(') + { + tree argtype_list = NULL_TREE; + str++; + while (str < limit && str[0] != ')') + { + tree argtype = promote_type (parse_signature_type (&str, limit)); + argtype_list = tree_cons (NULL_TREE, argtype, argtype_list); + } + if (str++, str >= limit) + fatal ("bad signature string"); + result_type = promote_type (parse_signature_type (&str, limit)); + result_type = build_function_type (result_type, + nreverse (argtype_list)); + } + else + result_type = parse_signature_type (&str, limit); + if (str != limit) + error ("junk at end of signature string"); + pop_obstacks (); + return result_type; +} + +/* Convert a signature to its type. + * Uses IDENTIFIER_SIGNATURE_TYPE as a cache (except for primitive types). + */ + +tree +get_type_from_signature (tree signature) +{ + unsigned char *sig = (unsigned char *) IDENTIFIER_POINTER (signature); + int len = IDENTIFIER_LENGTH (signature); + tree type; + /* Primitive types aren't cached. */ + if (len <= 1) + return parse_signature_string (sig, len); + type = IDENTIFIER_SIGNATURE_TYPE (signature); + if (type == NULL_TREE) + { + type = parse_signature_string (sig, len); + IDENTIFIER_SIGNATURE_TYPE (signature) = type; + } + return type; +} + +/* Return the signature string for the arguments of method type TYPE. */ + +tree +build_java_argument_signature (type) + tree type; +{ + extern struct obstack temporary_obstack; + tree sig = TYPE_ARGUMENT_SIGNATURE (type); + if (sig == NULL_TREE) + { + tree args = TYPE_ARG_TYPES (type); + if (TREE_CODE (type) == METHOD_TYPE) + args = TREE_CHAIN (args); /* Skip "this" argument. */ + for (; args != NULL_TREE; args = TREE_CHAIN (args)) + { + tree t = build_java_signature (TREE_VALUE (args)); + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t)); + } + obstack_1grow (&temporary_obstack, '\0'); + + sig = get_identifier (obstack_base (&temporary_obstack)); + TYPE_ARGUMENT_SIGNATURE (type) = sig; + obstack_free (&temporary_obstack, obstack_base (&temporary_obstack)); + } + return sig; +} + +/* Return the signature of the given TYPE. */ + +tree +build_java_signature (type) + tree type; +{ + tree sig, t; + push_obstacks (&permanent_obstack, &permanent_obstack); + while (TREE_CODE (type) == POINTER_TYPE) + type = TREE_TYPE (type); + if (TYPE_LANG_SPECIFIC (type) == NULL) + { + TYPE_LANG_SPECIFIC (type) = (struct lang_type *) + perm_calloc (1, sizeof (struct lang_type)); + + } + sig = TYPE_LANG_SPECIFIC (type)->signature; + if (sig == NULL_TREE) + { + char sg[2]; + switch (TREE_CODE (type)) + { + case BOOLEAN_TYPE: sg[0] = 'Z'; goto native; + case CHAR_TYPE: sg[0] = 'C'; goto native; + case VOID_TYPE: sg[0] = 'V'; goto native; + case INTEGER_TYPE: + switch (TYPE_PRECISION (type)) + { + case 8: sg[0] = 'B'; goto native; + case 16: sg[0] = 'S'; goto native; + case 32: sg[0] = 'I'; goto native; + case 64: sg[0] = 'J'; goto native; + default: goto bad_type; + } + case REAL_TYPE: + switch (TYPE_PRECISION (type)) + { + case 32: sg[0] = 'F'; goto native; + case 64: sg[0] = 'D'; goto native; + default: goto bad_type; + } + native: + sg[1] = 0; + sig = get_identifier (sg); + break; + case RECORD_TYPE: + if (TYPE_ARRAY_P (type)) + { + t = build_java_signature (TYPE_ARRAY_ELEMENT (type)); + sig = ident_subst (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t), + "[", 0, 0, ""); + } + else + { + t = DECL_NAME (TYPE_NAME (type)); + sig = ident_subst (IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t), + "L", '.', '/', ";"); + } + break; + case METHOD_TYPE: + case FUNCTION_TYPE: + { + extern struct obstack temporary_obstack; + sig = build_java_argument_signature (type); + obstack_1grow (&temporary_obstack, '('); + obstack_grow (&temporary_obstack, + IDENTIFIER_POINTER (sig), IDENTIFIER_LENGTH (sig)); + obstack_1grow (&temporary_obstack, ')'); + + t = build_java_signature (TREE_TYPE (type)); + obstack_grow0 (&temporary_obstack, + IDENTIFIER_POINTER (t), IDENTIFIER_LENGTH (t)); + + sig = get_identifier (obstack_base (&temporary_obstack)); + obstack_free (&temporary_obstack, + obstack_base (&temporary_obstack)); + } + break; + bad_type: + default: + fatal ("internal error - build_java_signature passed invalid type"); + } + TYPE_LANG_SPECIFIC (type)->signature = sig; + } + pop_obstacks (); + return sig; +} + +/* Save signature string SIG (an IDENTIFIER_NODE) in TYPE for future use. */ + +void +set_java_signature (type, sig) + tree type; + tree sig; +{ + tree old_sig; + while (TREE_CODE (type) == POINTER_TYPE) + type = TREE_TYPE (type); + if (TYPE_LANG_SPECIFIC (type) == NULL) + { + TYPE_LANG_SPECIFIC (type) = (struct lang_type *) + perm_calloc (1, sizeof (struct lang_type)); + + } + old_sig = TYPE_LANG_SPECIFIC (type)->signature; + if (old_sig != NULL_TREE && old_sig != sig) + fatal ("internal error - set_java_signature"); + TYPE_LANG_SPECIFIC (type)->signature = sig; +#if 0 /* careful about METHOD_TYPE */ + if (IDENTIFIER_SIGNATURE_TYPE (sig) == NULL_TREE && TREE_PERMANENT (type)) + IDENTIFIER_SIGNATURE_TYPE (sig) = type; +#endif +} + +/* Search in class CLAS (and its superclasses) for a method + matching METHOD_NAME and argument signature METHOD_SIGNATURE. + Return a FUNCTION_DECL on success, or NULL_TREE if none found. + (Contrast lookup_java_method, which takes into account return type.) */ + +tree +lookup_argument_method (clas, method_name, method_signature) + tree clas, method_name, method_signature; +{ + tree method; + while (clas != NULL_TREE) + { + for (method = TYPE_METHODS (clas); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree method_sig = build_java_argument_signature (TREE_TYPE (method)); + if (DECL_NAME (method) == method_name && method_sig == method_signature) + return method; + } + clas = CLASSTYPE_SUPER (clas); + } + return NULL_TREE; +} + +/* Search in class CLAS (and its superclasses) for a method + matching METHOD_NAME and signature METHOD_SIGNATURE. + Return a FUNCTION_DECL on success, or NULL_TREE if none found. + (Contrast lookup_argument_method, which ignores return type.) */ + +tree +lookup_java_method (clas, method_name, method_signature) + tree clas, method_name, method_signature; +{ + tree method; + while (clas != NULL_TREE) + { + for (method = TYPE_METHODS (clas); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree method_sig = build_java_signature (TREE_TYPE (method)); + if (DECL_NAME (method) == method_name && method_sig == method_signature) + return method; + } + clas = CLASSTYPE_SUPER (clas); + } + return NULL_TREE; +} + +/* Search in class CLAS (and its superclasses) for methods matching + METHOD_NAME and METHOD_SIGNATURE. Return a list of FUNCTION_DECLs. + When called from here, build_java_signature doesn't take the + returned type into account. */ + +tree +match_java_method (clas, method_name, method_signature) + tree clas, method_name, method_signature; +{ + tree method; + tree list = NULL_TREE; + while (clas != NULL_TREE) + { + for (method = TYPE_METHODS (clas); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree method_sig = build_java_argument_signature (TREE_TYPE (method)); + if (DECL_NAME (method) == method_name + && method_sig == method_signature) + list = tree_cons (NULL_TREE, method, list); + } + clas = CLASSTYPE_SUPER (clas); + } + return list; +} + +/* Search in class CLAS for a constructor matching METHOD_SIGNATURE. + Return a FUNCTION_DECL on success, or NULL_TREE if none found. */ + +tree +lookup_java_constructor (clas, method_signature) + tree clas, method_signature; +{ + tree method = TYPE_METHODS (clas); + for ( ; method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree method_sig = build_java_signature (TREE_TYPE (method)); + if (DECL_CONSTRUCTOR_P (method) && method_sig == method_signature) + return method; + } + return NULL_TREE; +} + +/* Return a type which is the Binary Numeric Promotion of the pair T1, + T2 and convert EXP1 and/or EXP2. See 5.6.2 Binary Numeric + Promotion. It assumes that both T1 and T2 are elligible to BNP. */ + +tree +binary_numeric_promotion (t1, t2, exp1, exp2) + tree t1; + tree t2; + tree *exp1; + tree *exp2; +{ + if (t1 == double_type_node || t2 == double_type_node) + { + if (t1 != double_type_node) + *exp1 = convert (double_type_node, *exp1); + if (t2 != double_type_node) + *exp2 = convert (double_type_node, *exp2); + return double_type_node; + } + if (t1 == float_type_node || t2 == float_type_node) + { + if (t1 != float_type_node) + *exp1 = convert (float_type_node, *exp1); + if (t2 != float_type_node) + *exp2 = convert (float_type_node, *exp2); + return float_type_node; + } + if (t1 == long_type_node || t2 == long_type_node) + { + if (t1 != long_type_node) + *exp1 = convert (long_type_node, *exp1); + if (t2 != long_type_node) + *exp2 = convert (long_type_node, *exp2); + return long_type_node; + } + + if (t1 != int_type_node) + *exp1 = convert (int_type_node, *exp1); + if (t2 != int_type_node) + *exp2 = convert (int_type_node, *exp2); + return int_type_node; +} diff --git a/gcc/java/verify.c b/gcc/java/verify.c new file mode 100644 index 00000000000..82a081f079c --- /dev/null +++ b/gcc/java/verify.c @@ -0,0 +1,1239 @@ +/* Handle verification of bytecoded methods for the GNU compiler for + the Java(TM) language. + Copyright (C) 1997 Free Software Foundation, Inc. + +This file is part of GNU CC. + +GNU CC 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, +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 +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. */ + +#include +#include "config.h" +#include "tree.h" +#include "java-tree.h" +#include "javaop.h" +#include "java-opcodes.h" +#include "jcf.h" +#include "java-except.h" + +extern int stack_pointer; + +/* During verification, start of the current subroutine (jsr target). */ +tree current_subr; + +/* A list of pending blocks, chained using LABEL_PENDING_CHAIN. + A pending block is one that has LABEL_CHANGED set, which means + it requires (re-) verification. */ +tree pending_blocks; + +/* Append TARGET_LABEL to the pending_block stack unless already in it. */ + +void +push_pending_label (target_label) + tree target_label; +{ + if (! LABEL_CHANGED (target_label)) + { + LABEL_PENDING_CHAIN (target_label) = pending_blocks; + pending_blocks = target_label; + LABEL_CHANGED (target_label) = 1; + } +} + +/* Note that TARGET_LABEL is a possible successor instruction. + Merge the type state etc. + Return NULL on sucess, or an error message on failure. */ + +static char * +check_pending_block (target_label) + tree target_label; +{ + int changed = merge_type_state (target_label); + + if (changed) + { + if (changed < 0) + return "types could not be merged"; + push_pending_label (target_label); + } + + if (current_subr == NULL) + { + if (LABEL_IN_SUBR (target_label)) + return "might transfer control into subroutine"; + } + else + { + if (LABEL_IN_SUBR (target_label)) + { + if (LABEL_SUBR_START (target_label) != current_subr) + return "transfer out of subroutine"; + } + else if (! LABEL_VERIFIED (target_label)) + { + LABEL_IN_SUBR (target_label) = 1; + LABEL_SUBR_START (target_label) = current_subr; + } + else + return "transfer out of subroutine"; + } + return NULL; +} + +/* Return the "merged" types of TYPE1 and TYPE2. + If either is primitive, the other must match (after promotion to int). + For reference types, return the common super-class. + Return TYPE_UNKNOWN if the types cannot be merged. */ + +tree +merge_types (type1, type2) + tree type1, type2; +{ + if (type1 == type2) + return type1; + if (type1 == TYPE_UNKNOWN || type2 == TYPE_UNKNOWN + || type1 == TYPE_RETURN_ADDR || type2 == TYPE_RETURN_ADDR) + return TYPE_UNKNOWN; + if (TREE_CODE (type1) == POINTER_TYPE && TREE_CODE (type2) == POINTER_TYPE) + { + int depth1, depth2; + tree tt1, tt2; + /* ptr_type_node is only used for a null reference, + which is compatible with any reference type. */ + if (type1 == ptr_type_node || type2 == object_ptr_type_node) + return type2; + if (type2 == ptr_type_node || type1 == object_ptr_type_node) + return type1; + + tt1 = HANDLE_TO_CLASS_TYPE (TREE_TYPE (type1)); + tt2 = HANDLE_TO_CLASS_TYPE (TREE_TYPE (type2)); + + if (TYPE_ARRAY_P (tt1) || TYPE_ARRAY_P (tt2)) + { + if (TYPE_ARRAY_P (tt1) == TYPE_ARRAY_P (tt2)) + { + tree el_type1 = TYPE_ARRAY_ELEMENT (tt1); + tree el_type2 = TYPE_ARRAY_ELEMENT (tt2); + tree el_type = NULL_TREE; + if (el_type1 == el_type2) + el_type = el_type1; + else if (TREE_CODE (el_type1) == POINTER_TYPE + && TREE_CODE (el_type2) == POINTER_TYPE) + el_type = merge_types (el_type1, el_type2); + if (el_type != NULL_TREE) + { + HOST_WIDE_INT len1 = java_array_type_length (tt1); + HOST_WIDE_INT len2 = java_array_type_length (tt2); + if (len1 != len2) + len1 = -1; + else if (el_type1 == el_type2) + return type1; + return promote_type (build_java_array_type (el_type, len1)); + } + } + return object_ptr_type_node; + } + type1 = tt1; + type2 = tt2; + + depth1 = class_depth (type1); + depth2 = class_depth (type2); + for ( ; depth1 > depth2; depth1--) + type1 = TYPE_BINFO_BASETYPE (type1, 0); + for ( ; depth2 > depth1; depth2--) + type2 = TYPE_BINFO_BASETYPE (type2, 0); + while (type1 != type2) + { + type1 = TYPE_BINFO_BASETYPE (type1, 0); + type2 = TYPE_BINFO_BASETYPE (type2, 0); + } + return promote_type (type1); + } + if (INTEGRAL_TYPE_P (type1) && INTEGRAL_TYPE_P (type2) + && TYPE_PRECISION (type1) <= 32 && TYPE_PRECISION (type2) <= 32) + return int_type_node; + return TYPE_UNKNOWN; +} + +/* Merge the current type state with that at LABEL. + Return -1 the the states are incompatible (i.e. on error), + 0 if there was no change, and 1 if there was a change. */ + +int +merge_type_state (label) + tree label; +{ + int nlocals = DECL_MAX_LOCALS(current_function_decl); + int cur_length = stack_pointer + nlocals; + tree vec = LABEL_TYPE_STATE (label); + tree return_map; + if (vec == NULL_TREE) + { + vec = make_tree_vec (cur_length); + LABEL_TYPE_STATE (label) = vec; + while (--cur_length >= 0) + TREE_VEC_ELT (vec, cur_length) = type_map [cur_length]; + return 1; + } + else + { + int i; + int changed = 0; + if (LABEL_IS_SUBR_START (label) && LABEL_VERIFIED (label) + && current_subr != label) + return_map = LABEL_RETURN_TYPE_STATE (label); + else + return_map = NULL_TREE; + if (TREE_VEC_LENGTH (vec) != cur_length) + { + return -1; + } + for (i = 0; i < cur_length; i++) + { + tree old_type = TREE_VEC_ELT (vec, i); + tree new_type = merge_types (old_type, type_map [i]); + if (TREE_VEC_ELT (vec, i) != new_type) + { + /* If there has been a change, note that since we must re-verify. + However, if the label is the start of a subroutine, + we don't care about local variables that are neither + set nor used in the sub-routine. */ + if (return_map == NULL_TREE || i >= nlocals + || TREE_VEC_ELT (return_map, i) != TYPE_UNUSED + || (TYPE_IS_WIDE (new_type) + && TREE_VEC_ELT (return_map, i+1) != TYPE_UNUSED)) + changed = 1; + } + TREE_VEC_ELT (vec, i) = new_type; + if (new_type == TYPE_UNKNOWN) + { + if (i >= nlocals) + return -1; + } + else if (TYPE_IS_WIDE (new_type)) + i++; + } + return changed; + } +} + +/* Handle dup-like operations. */ + +static void +type_stack_dup (size, offset) + int size, offset; +{ + tree type[4]; + int index; + if (size + offset > stack_pointer) + error ("stack underflow - dup* operation"); + for (index = 0; index < size + offset; index++) + { + type[index] = stack_type_map[stack_pointer - 1]; + if (type[index] == void_type_node) + { + index++; + type[index] = stack_type_map[stack_pointer - 2]; + if (! TYPE_IS_WIDE (type[index])) + fatal ("internal error - dup operation"); + if (index == size || index == size + offset) + fatal ("dup operation splits 64-bit number"); + } + pop_type (type[index]); + } + for (index = size; --index >= 0; ) + { + if (type[index] != void_type_node) + push_type (type[index]); + } + + for (index = size + offset; --index >= 0; ) + { + if (type[index] != void_type_node) + push_type (type[index]); + } +} + +/* This causes the next iteration to ignore the next instruction + and look for some other unhandled instruction. */ +#define INVALIDATE_PC (prevpc = -1, oldpc = PC, PC = INVALID_PC) +#define INVALID_PC (-1) + +#define VERIFICATION_ERROR(MESSAGE) \ + do { message = MESSAGE; goto verify_error; } while (0) + +#define PUSH_PENDING(LABEL) \ + do { if ((message = check_pending_block (LABEL)) != NULL) \ + goto verify_error; } while (0) + +#ifdef __GNUC__ +#define CHECK_PC_IN_RANGE(PC) ({if (PC < 0 || PC > length) goto bad_pc; 1;}) +#else +#define CHECK_PC_IN_RANGE(PC) (PC < 0 || PC > length ? \ + (fatal("Bad byte codes.\n"), 0) : 1) +#endif + +#define BCODE byte_ops + +/* Verify the bytecodes of the current method. + Return 1 on sucess, 0 on failure. */ +int +verify_jvm_instructions (jcf, byte_ops, length) + JCF* jcf; + unsigned char* byte_ops; + long length; +{ + tree label; + int wide = 0; + int op_code; + int PC; + int oldpc; /* PC of start of instruction. */ + int prevpc; /* If >= 0, PC of previous instruction. */ + char *message; + int i; + register unsigned char *p; + struct eh_range *prev_eh_ranges = NULL_EH_RANGE; + struct eh_range *eh_ranges; + + jint int_value = -1; + + pending_blocks = NULL_TREE; + + /* Handle the exception table. */ + method_init_exceptions (); + JCF_SEEK (jcf, DECL_CODE_OFFSET (current_function_decl) + length); + i = JCF_readu2 (jcf); + + /* We read the exception backwards. */ + p = jcf->read_ptr + 8 * i; + while (--i >= 0) + { + int start_pc = GET_u2 (p-8); + int end_pc = GET_u2 (p-6); + int handler_pc = GET_u2 (p-4); + int catch_type = GET_u2 (p-2); + p -= 8; + + if (start_pc < 0 || start_pc >= length + || end_pc < 0 || end_pc > length || start_pc >= end_pc + || handler_pc < 0 || handler_pc >= length + || (handler_pc >= start_pc && handler_pc < end_pc) + || ! (instruction_bits [start_pc] & BCODE_INSTRUCTION_START) + || ! (instruction_bits [end_pc] & BCODE_INSTRUCTION_START) + || ! (instruction_bits [handler_pc] & BCODE_INSTRUCTION_START)) + { + error ("bad pc in exception_table"); + return 0; + } + + if (! add_handler (start_pc, end_pc, + lookup_label (handler_pc), + catch_type == 0 ? NULL_TREE + : get_class_constant (jcf, catch_type))) + { + error ("overlapping exception ranges are not supported"); + return 0; + } + + instruction_bits [handler_pc] |= BCODE_EXCEPTION_TARGET; + } + + for (PC = 0;;) + { + int index; + tree type, tmp; + if (((PC != INVALID_PC + && instruction_bits [PC] & BCODE_TARGET) != 0) + || PC == 0) + { + PUSH_PENDING (lookup_label (PC)); + INVALIDATE_PC; + } + if (PC == INVALID_PC) + { + label = pending_blocks; + if (label == NULL_TREE) + break; /* We're done! */ + pending_blocks = LABEL_PENDING_CHAIN (label); + LABEL_CHANGED (label) = 0; + + if (LABEL_IN_SUBR (label)) + current_subr = LABEL_SUBR_START (label); + else + current_subr = NULL_TREE; + + /* Restore type_map and stack_pointer from + LABEL_TYPE_STATE (label), and continue + compiling from there. */ + load_type_state (label); + PC = LABEL_PC (label); + } + else if (PC >= length) + VERIFICATION_ERROR ("falling through end of method"); + + oldpc = PC; + + if (!(instruction_bits [PC] & BCODE_INSTRUCTION_START) && ! wide) + VERIFICATION_ERROR ("PC not at instruction start"); + + instruction_bits[PC] |= BCODE_VERIFIED; + + eh_ranges = find_handler (oldpc); + + op_code = byte_ops[PC++]; + switch (op_code) + { + int is_static, is_putting; + case OPCODE_nop: + break; + case OPCODE_iconst_m1: + case OPCODE_iconst_0: case OPCODE_iconst_1: case OPCODE_iconst_2: + case OPCODE_iconst_3: case OPCODE_iconst_4: case OPCODE_iconst_5: + i = op_code - OPCODE_iconst_0; + goto push_int; + push_int: + if (byte_ops[PC] == OPCODE_newarray + || byte_ops[PC] == OPCODE_newarray) + int_value = i; + push_type (int_type_node); break; + case OPCODE_lconst_0: case OPCODE_lconst_1: + push_type (long_type_node); break; + case OPCODE_fconst_0: case OPCODE_fconst_1: case OPCODE_fconst_2: + push_type (float_type_node); break; + case OPCODE_dconst_0: case OPCODE_dconst_1: + push_type (double_type_node); break; + case OPCODE_bipush: + i = IMMEDIATE_s1; + goto push_int; + case OPCODE_sipush: + i = IMMEDIATE_s2; + goto push_int; + case OPCODE_iload: type = int_type_node; goto general_load; + case OPCODE_lload: type = long_type_node; goto general_load; + case OPCODE_fload: type = float_type_node; goto general_load; + case OPCODE_dload: type = double_type_node; goto general_load; + case OPCODE_aload: type = ptr_type_node; goto general_load; + general_load: + index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; + wide = 0; + goto load; + case OPCODE_iload_0: type = int_type_node; index = 0; goto load; + case OPCODE_iload_1: type = int_type_node; index = 1; goto load; + case OPCODE_iload_2: type = int_type_node; index = 2; goto load; + case OPCODE_iload_3: type = int_type_node; index = 3; goto load; + case OPCODE_lload_0: type = long_type_node; index = 0; goto load; + case OPCODE_lload_1: type = long_type_node; index = 1; goto load; + case OPCODE_lload_2: type = long_type_node; index = 2; goto load; + case OPCODE_lload_3: type = long_type_node; index = 3; goto load; + case OPCODE_fload_0: type = float_type_node; index = 0; goto load; + case OPCODE_fload_1: type = float_type_node; index = 1; goto load; + case OPCODE_fload_2: type = float_type_node; index = 2; goto load; + case OPCODE_fload_3: type = float_type_node; index = 3; goto load; + case OPCODE_dload_0: type = double_type_node; index = 0; goto load; + case OPCODE_dload_1: type = double_type_node; index = 1; goto load; + case OPCODE_dload_2: type = double_type_node; index = 2; goto load; + case OPCODE_dload_3: type = double_type_node; index = 3; goto load; + case OPCODE_aload_0: type = ptr_type_node; index = 0; goto load; + case OPCODE_aload_1: type = ptr_type_node; index = 1; goto load; + case OPCODE_aload_2: type = ptr_type_node; index = 2; goto load; + case OPCODE_aload_3: type = ptr_type_node; index = 3; goto load; + load: + if (index < 0 + || (index + TYPE_IS_WIDE (type) + >= DECL_MAX_LOCALS (current_function_decl))) + VERIFICATION_ERROR ("invalid local variable index in load"); + tmp = type_map[index]; + if (tmp == TYPE_UNKNOWN || tmp == TYPE_SECOND + || (TYPE_IS_WIDE (type) + && type_map[index+1] != void_type_node) + || (type == ptr_type_node + ? TREE_CODE (tmp) != POINTER_TYPE + : type == int_type_node + ? (! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32) + : type != tmp)) + VERIFICATION_ERROR("invalid local variable type in load"); + push_type (tmp); + goto note_used; + case OPCODE_istore: type = int_type_node; goto general_store; + case OPCODE_lstore: type = long_type_node; goto general_store; + case OPCODE_fstore: type = float_type_node; goto general_store; + case OPCODE_dstore: type = double_type_node; goto general_store; + case OPCODE_astore: type = ptr_type_node; goto general_store; + general_store: + index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; + wide = 0; + goto store; + case OPCODE_istore_0: type = int_type_node; index = 0; goto store; + case OPCODE_istore_1: type = int_type_node; index = 1; goto store; + case OPCODE_istore_2: type = int_type_node; index = 2; goto store; + case OPCODE_istore_3: type = int_type_node; index = 3; goto store; + case OPCODE_lstore_0: type = long_type_node; index=0; goto store; + case OPCODE_lstore_1: type = long_type_node; index=1; goto store; + case OPCODE_lstore_2: type = long_type_node; index=2; goto store; + case OPCODE_lstore_3: type = long_type_node; index=3; goto store; + case OPCODE_fstore_0: type=float_type_node; index=0; goto store; + case OPCODE_fstore_1: type=float_type_node; index=1; goto store; + case OPCODE_fstore_2: type=float_type_node; index=2; goto store; + case OPCODE_fstore_3: type=float_type_node; index=3; goto store; + case OPCODE_dstore_0: type=double_type_node; index=0; goto store; + case OPCODE_dstore_1: type=double_type_node; index=1; goto store; + case OPCODE_dstore_2: type=double_type_node; index=2; goto store; + case OPCODE_dstore_3: type=double_type_node; index=3; goto store; + case OPCODE_astore_0: type = ptr_type_node; index = 0; goto store; + case OPCODE_astore_1: type = ptr_type_node; index = 1; goto store; + case OPCODE_astore_2: type = ptr_type_node; index = 2; goto store; + case OPCODE_astore_3: type = ptr_type_node; index = 3; goto store; + store: + if (index < 0 + || (index + TYPE_IS_WIDE (type) + >= DECL_MAX_LOCALS (current_function_decl))) + { + VERIFICATION_ERROR ("invalid local variable index in store"); + return 0; + } + type = pop_type (type); + type_map[index] = type; + + /* If local variable changed, we need to reconsider eh handlers. */ + prev_eh_ranges = NULL_EH_RANGE; + + /* Allocate decl and rtx for this variable now, so if we're not + optmizing, we get a temporary that survives the whole method. */ + find_local_variable (index, type, oldpc); + + if (TYPE_IS_WIDE (type)) + type_map[index+1] = TYPE_SECOND; + /* ... fall through to note_used ... */ + note_used: + /* For store or load, note that local variable INDEX is used. + This is needed to verify try-finally sub-routines. */ + if (current_subr) + { + tree vec = LABEL_RETURN_TYPE_STATE (current_subr); + tree subr_vec = LABEL_TYPE_STATE (current_subr); + int len = 1 + TYPE_IS_WIDE (type); + while (--len >= 0) + { + if (TREE_VEC_ELT (vec, index) == TYPE_UNUSED) + TREE_VEC_ELT (vec, index) = TREE_VEC_ELT (subr_vec, index); + } + } + break; + case OPCODE_iadd: + case OPCODE_iand: + case OPCODE_idiv: + case OPCODE_imul: + case OPCODE_ior: + case OPCODE_irem: + case OPCODE_ishl: + case OPCODE_ishr: + case OPCODE_isub: + case OPCODE_iushr: + case OPCODE_ixor: + type = int_type_node; goto binop; + case OPCODE_ineg: + case OPCODE_i2c: + case OPCODE_i2b: + case OPCODE_i2s: + type = int_type_node; goto unop; + case OPCODE_ladd: + case OPCODE_land: + case OPCODE_ldiv: + case OPCODE_lsub: + case OPCODE_lmul: + case OPCODE_lrem: + case OPCODE_lor: + case OPCODE_lxor: + type = long_type_node; goto binop; + case OPCODE_lneg: + type = long_type_node; goto unop; + case OPCODE_fadd: case OPCODE_fsub: + case OPCODE_fmul: case OPCODE_fdiv: case OPCODE_frem: + type = float_type_node; goto binop; + case OPCODE_fneg: + type = float_type_node; goto unop; + case OPCODE_dadd: case OPCODE_dsub: + case OPCODE_dmul: case OPCODE_ddiv: case OPCODE_drem: + type = double_type_node; goto binop; + case OPCODE_dneg: + type = double_type_node; goto unop; + unop: + pop_type (type); + push_type (type); + break; + binop: + pop_type (type); + pop_type (type); + push_type (type); + break; + case OPCODE_lshl: + case OPCODE_lshr: + case OPCODE_lushr: + pop_type (int_type_node); + pop_type (long_type_node); + push_type (long_type_node); + break; + case OPCODE_iinc: + index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; + PC += wide + 1; + wide = 0; + if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl)) + VERIFICATION_ERROR ("invalid local variable index in iinc"); + tmp = type_map[index]; + if (! INTEGRAL_TYPE_P (tmp) || TYPE_PRECISION (tmp) > 32) + VERIFICATION_ERROR ("invalid local variable type in iinc"); + break; + case OPCODE_i2l: + pop_type (int_type_node); push_type (long_type_node); break; + case OPCODE_i2f: + pop_type (int_type_node); push_type (float_type_node); break; + case OPCODE_i2d: + pop_type (int_type_node); push_type (double_type_node); break; + case OPCODE_l2i: + pop_type (long_type_node); push_type (int_type_node); break; + case OPCODE_l2f: + pop_type (long_type_node); push_type (float_type_node); break; + case OPCODE_l2d: + pop_type (long_type_node); push_type (double_type_node); break; + case OPCODE_f2i: + pop_type (float_type_node); push_type (int_type_node); break; + case OPCODE_f2l: + pop_type (float_type_node); push_type (long_type_node); break; + case OPCODE_f2d: + pop_type (float_type_node); push_type (double_type_node); break; + case OPCODE_d2i: + pop_type (double_type_node); push_type (int_type_node); break; + case OPCODE_d2l: + pop_type (double_type_node); push_type (long_type_node); break; + case OPCODE_d2f: + pop_type (double_type_node); push_type (float_type_node); break; + case OPCODE_lcmp: + type = long_type_node; goto compare; + case OPCODE_fcmpl: + case OPCODE_fcmpg: + type = float_type_node; goto compare; + case OPCODE_dcmpl: + case OPCODE_dcmpg: + type = double_type_node; goto compare; + compare: + pop_type (type); pop_type (type); + push_type (int_type_node); break; + case OPCODE_ifeq: + case OPCODE_ifne: + case OPCODE_iflt: + case OPCODE_ifge: + case OPCODE_ifgt: + case OPCODE_ifle: + pop_type (int_type_node); goto cond; + case OPCODE_ifnull: + case OPCODE_ifnonnull: + pop_type (ptr_type_node ); goto cond; + case OPCODE_if_icmpeq: + case OPCODE_if_icmpne: + case OPCODE_if_icmplt: + case OPCODE_if_icmpge: + case OPCODE_if_icmpgt: + case OPCODE_if_icmple: + pop_type (int_type_node); pop_type (int_type_node); goto cond; + case OPCODE_if_acmpeq: + case OPCODE_if_acmpne: + pop_type (object_ptr_type_node); pop_type (object_ptr_type_node); + goto cond; + cond: + PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2)); + break; + case OPCODE_goto: + PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s2)); + INVALIDATE_PC; + break; + case OPCODE_wide: + switch (byte_ops[PC]) + { + case OPCODE_iload: case OPCODE_lload: + case OPCODE_fload: case OPCODE_dload: case OPCODE_aload: + case OPCODE_istore: case OPCODE_lstore: + case OPCODE_fstore: case OPCODE_dstore: case OPCODE_astore: + case OPCODE_iinc: + case OPCODE_ret: + wide = 1; + break; + default: + VERIFICATION_ERROR ("invalid use of wide instruction"); + } + break; + case OPCODE_ireturn: type = int_type_node; goto ret; + case OPCODE_lreturn: type = long_type_node; goto ret; + case OPCODE_freturn: type = float_type_node; goto ret; + case OPCODE_dreturn: type = double_type_node; goto ret; + case OPCODE_areturn: type = ptr_type_node; goto ret; + ret: + pop_type (type); + /* ... fall through ... */ + case OPCODE_return: + INVALIDATE_PC; + break; + case OPCODE_getstatic: is_putting = 0; is_static = 1; goto field; + case OPCODE_putstatic: is_putting = 1; is_static = 1; goto field; + case OPCODE_getfield: is_putting = 0; is_static = 0; goto field; + case OPCODE_putfield: is_putting = 1; is_static = 0; goto field; + field: + { + int index = IMMEDIATE_u2; + tree self_type = get_class_constant + (jcf, COMPONENT_REF_CLASS_INDEX (¤t_jcf->cpool, index)); + tree field_name = COMPONENT_REF_NAME (¤t_jcf->cpool, index); + tree field_signature = COMPONENT_REF_SIGNATURE (¤t_jcf->cpool, index); + tree field_type = get_type_from_signature (field_signature); + if (is_putting) + pop_type (field_type); + if (! is_static) + { + /* Defer actual checking until next pass. */ + pop_type (ptr_type_node); + } + if (! is_putting) + push_type (field_type); + break; + } + case OPCODE_new: + push_type (get_class_constant (jcf, IMMEDIATE_u2)); + break; + case OPCODE_dup: type_stack_dup (1, 0); break; + case OPCODE_dup_x1: type_stack_dup (1, 1); break; + case OPCODE_dup_x2: type_stack_dup (1, 2); break; + case OPCODE_dup2: type_stack_dup (2, 0); break; + case OPCODE_dup2_x1: type_stack_dup (2, 1); break; + case OPCODE_dup2_x2: type_stack_dup (2, 2); break; + case OPCODE_pop: index = 1; goto pop; + case OPCODE_pop2: index = 2; goto pop; + pop: + if (stack_pointer < index) + VERIFICATION_ERROR ("stack underflow"); + stack_pointer -= index; + break; + case OPCODE_swap: + if (stack_pointer < 2) + VERIFICATION_ERROR ("stack underflow (in swap)"); + else + { + tree type1 = stack_type_map[stack_pointer - 1]; + tree type2 = stack_type_map[stack_pointer - 2]; + if (type1 == void_type_node || type2 == void_type_node) + VERIFICATION_ERROR ("verifier (swap): double or long value"); + stack_type_map[stack_pointer - 2] = type1; + stack_type_map[stack_pointer - 1] = type2; + } + break; + case OPCODE_ldc: index = IMMEDIATE_u1; goto ldc; + case OPCODE_ldc2_w: + case OPCODE_ldc_w: + index = IMMEDIATE_u2; goto ldc; + ldc: + if (index <= 0 || index >= JPOOL_SIZE(current_jcf)) + VERIFICATION_ERROR ("bad constant pool index in ldc"); + int_value = -1; + switch (JPOOL_TAG (current_jcf, index) & ~CONSTANT_ResolvedFlag) + { + case CONSTANT_Integer: type = int_type_node; goto check_ldc; + case CONSTANT_Float: type = float_type_node; goto check_ldc; + case CONSTANT_String: type = string_type_node; goto check_ldc; + case CONSTANT_Long: type = long_type_node; goto check_ldc; + case CONSTANT_Double: type = double_type_node; goto check_ldc; + check_ldc: + if (TYPE_IS_WIDE (type) == (op_code == OPCODE_ldc2_w)) + break; + /* ... else fall through ... */ + default: + bad_ldc: + VERIFICATION_ERROR ("bad constant pool tag in ldc"); + } + if (type == int_type_node) + { + i = TREE_INT_CST_LOW (get_constant (current_jcf, index)); + goto push_int; + } + push_type (type); + break; + + case OPCODE_invokevirtual: + case OPCODE_invokespecial: + case OPCODE_invokestatic: + case OPCODE_invokeinterface: + { + int index = IMMEDIATE_u2; + tree sig = COMPONENT_REF_SIGNATURE (¤t_jcf->cpool, index); + tree self_type = get_class_constant + (current_jcf, COMPONENT_REF_CLASS_INDEX (¤t_jcf->cpool, + index)); + tree method_name = COMPONENT_REF_NAME (¤t_jcf->cpool, index); + tree method_type; + method_type = parse_signature_string (IDENTIFIER_POINTER (sig), + IDENTIFIER_LENGTH (sig)); + if (TREE_CODE (method_type) != FUNCTION_TYPE) + VERIFICATION_ERROR ("bad method signature"); + pop_argument_types (TYPE_ARG_TYPES (method_type)); + + /* Can't invoke */ + if (method_name == clinit_identifier_node) + VERIFICATION_ERROR ("invoke opcode can't invoke "); + /* Apart invokespecial, can't invoke */ + if (op_code != OPCODE_invokespecial + && method_name == init_identifier_node) + VERIFICATION_ERROR ("invoke opcode can't invoke "); + + if (op_code != OPCODE_invokestatic) + pop_type (self_type); + + switch (op_code) + { + case OPCODE_invokeinterface: + { + int nargs = IMMEDIATE_u1; + int notZero = IMMEDIATE_u1; + + if (!nargs || notZero) + VERIFICATION_ERROR + ("invalid argument number in invokeinterface"); + break; + } + } + + if (TREE_TYPE (method_type) != void_type_node) + push_type (TREE_TYPE (method_type)); + break; + } + + case OPCODE_arraylength: + /* Type checking actually made during code generation */ + pop_type( ptr_type_node ); + push_type( int_type_node ); + break; + + /* Q&D verification *or* more checking done during code generation + for byte/boolean/char/short, the value popped is a int coerced + into the right type before being stored. */ + case OPCODE_iastore: type = int_type_node; goto astore; + case OPCODE_lastore: type = long_type_node; goto astore; + case OPCODE_fastore: type = float_type_node; goto astore; + case OPCODE_dastore: type = double_type_node; goto astore; + case OPCODE_aastore: type = ptr_type_node; goto astore; + case OPCODE_bastore: type = int_type_node; goto astore; + case OPCODE_castore: type = int_type_node; goto astore; + case OPCODE_sastore: type = int_type_node; goto astore; + astore: + /* FIXME - need better verification here */ + pop_type (type); /* new value */ + pop_type (int_type_node); /* index */ + pop_type (ptr_type_node); /* array */ + break; + + /* Q&D verification *or* more checking done during code generation + for byte/boolean/char/short, the value pushed is a int. */ + case OPCODE_iaload: type = int_type_node; goto aload; + case OPCODE_laload: type = long_type_node; goto aload; + case OPCODE_faload: type = float_type_node; goto aload; + case OPCODE_daload: type = double_type_node; goto aload; + case OPCODE_aaload: type = ptr_type_node; goto aload; + case OPCODE_baload: type = promote_type (byte_type_node); goto aload; + case OPCODE_caload: type = promote_type (char_type_node); goto aload; + case OPCODE_saload: type = promote_type (short_type_node); goto aload; + aload: + pop_type (int_type_node); + type = pop_type (ptr_type_node); + if (! is_array_type_p (type)) + VERIFICATION_ERROR ("array load from non-array type"); + push_type (TYPE_ARRAY_ELEMENT (TREE_TYPE (type))); + break; + + case OPCODE_anewarray: + type = get_class_constant (current_jcf, IMMEDIATE_u2); + type = promote_type (type); + goto newarray; + + case OPCODE_newarray: + index = IMMEDIATE_u1; + type = decode_newarray_type (index); + if (type == NULL_TREE) + VERIFICATION_ERROR ("invalid type code in newarray opcode"); + goto newarray; + + newarray: + if (int_value >= 0 && prevpc >= 0) + { + /* If previous instruction pushed int constant, + we want to use it. */ + switch (byte_ops[prevpc]) + { + case OPCODE_iconst_0: case OPCODE_iconst_1: + case OPCODE_iconst_2: case OPCODE_iconst_3: + case OPCODE_iconst_4: case OPCODE_iconst_5: + case OPCODE_bipush: case OPCODE_sipush: + case OPCODE_ldc: case OPCODE_ldc_w: + break; + default: + int_value = -1; + } + } + else + int_value = -1; + type = build_java_array_type (type, int_value); + pop_type (int_type_node); + push_type (type); + break; + + case OPCODE_multianewarray: + { + int ndim, i; + index = IMMEDIATE_u2; + ndim = IMMEDIATE_u1; + + if( ndim < 1 ) + VERIFICATION_ERROR ("number of dimension lower that 1 in multianewarray" ); + + for( i = 0; i < ndim; i++ ) + pop_type (int_type_node); + push_type (get_class_constant (current_jcf, index)); + break; + } + + case OPCODE_aconst_null: + push_type (ptr_type_node); + break; + + case OPCODE_athrow: + pop_type (throwable_type_node); + INVALIDATE_PC; + break; + + case OPCODE_checkcast: + pop_type (ptr_type_node); + type = get_class_constant (current_jcf, IMMEDIATE_u2); + push_type (type); + break; + case OPCODE_instanceof: + pop_type (ptr_type_node); + get_class_constant (current_jcf, IMMEDIATE_u2); + push_type (integer_type_node); + break; + + case OPCODE_tableswitch: + { + jint default_val, low, high; + + pop_type (integer_type_node); + while (PC%4) + { + if (byte_ops[PC++]) + VERIFICATION_ERROR ("bad alignment in tableswitch pad"); + } + PUSH_PENDING (lookup_label (oldpc+IMMEDIATE_s4)); + low = IMMEDIATE_s4; + high = IMMEDIATE_s4; + + if (low > high) + VERIFICATION_ERROR ("unsorted low/high value in tableswitch"); + + while (low++ <= high) + PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); + break; + } + + case OPCODE_lookupswitch: + { + jint npairs, last, not_registered = 1; + + pop_type (integer_type_node); + while (PC%4) + { + if (byte_ops[PC++]) + VERIFICATION_ERROR ("bad alignment in lookupswitch pad"); + } + + PUSH_PENDING (lookup_label (oldpc+IMMEDIATE_s4)); + npairs = IMMEDIATE_s4; + + if (npairs < 0) + VERIFICATION_ERROR ("invalid number of targets in lookupswitch"); + + while (npairs--) + { + int match = IMMEDIATE_s4; + if (not_registered) + not_registered = 0; + else if (last >= match) + VERIFICATION_ERROR ("unsorted match value in lookupswitch"); + + last = match; + PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); + } + break; + } + + case OPCODE_monitorenter: + /* fall thru */ + case OPCODE_monitorexit: + pop_type (ptr_type_node); + break; + + case OPCODE_goto_w: + PUSH_PENDING (lookup_label (oldpc + IMMEDIATE_s4)); + INVALIDATE_PC; + break; + + case OPCODE_jsr: + { + tree target = lookup_label (oldpc + IMMEDIATE_s2); + tree return_label = lookup_label (PC); + push_type (return_address_type_node); + if (! LABEL_VERIFIED (target)) + { + /* first time seen */ + tree return_type_map; + int nlocals = DECL_MAX_LOCALS (current_function_decl); + index = nlocals + DECL_MAX_STACK (current_function_decl); + return_type_map = make_tree_vec (index); + while (--index >= nlocals) + TREE_VEC_ELT (return_type_map, index) = TYPE_UNKNOWN; + while (--index >= 0) + TREE_VEC_ELT (return_type_map, index) = TYPE_UNUSED; + LABEL_RETURN_LABEL (target) + = build_decl (LABEL_DECL, NULL_TREE, TREE_TYPE (target)); + LABEL_PC (LABEL_RETURN_LABEL (target)) = -1; + LABEL_RETURN_TYPE_STATE (target) = return_type_map; + LABEL_IS_SUBR_START (target) = 1; + LABEL_IN_SUBR (target) = 1; + LABEL_SUBR_START (target) = target; + LABEL_SUBR_CONTEXT (target) = current_subr; + } + else if (! LABEL_IS_SUBR_START (target) + || LABEL_SUBR_CONTEXT (target) != current_subr) + VERIFICATION_ERROR ("label part of different subroutines"); + + i = merge_type_state (target); + if (i != 0) + { + if (i < 0) + VERIFICATION_ERROR ("types could not be merged at jsr"); + push_pending_label (target); + } + current_subr = target; + + /* Chain return_pc onto LABEL_RETURN_LABELS (target) if needed. */ + if (! value_member (return_label, LABEL_RETURN_LABELS (target))) + { + LABEL_RETURN_LABELS (target) + = tree_cons (NULL_TREE, return_label, + LABEL_RETURN_LABELS (target)); + } + + if (LABEL_VERIFIED (target)) + { + tree return_map = LABEL_RETURN_TYPE_STATE (target); + int len = TREE_VEC_LENGTH (return_map); + stack_pointer = len - DECL_MAX_LOCALS (current_function_decl); + while (--len >= 0) + { + if (TREE_VEC_ELT (return_map, len) != TYPE_UNUSED) + type_map[len] = TREE_VEC_ELT (return_map, len); + } + current_subr = LABEL_SUBR_CONTEXT (target); + PUSH_PENDING (return_label); + } + + INVALIDATE_PC; + } + break; + case OPCODE_ret: + if (current_subr == NULL) + VERIFICATION_ERROR ("ret instruction not in a jsr subroutine"); + else + { + tree ret_map = LABEL_RETURN_TYPE_STATE (current_subr); + tree caller = LABEL_SUBR_CONTEXT (current_subr); + int size = DECL_MAX_LOCALS(current_function_decl)+stack_pointer; + index = wide ? IMMEDIATE_u2 : IMMEDIATE_u1; + wide = 0; + INVALIDATE_PC; + if (index < 0 || index >= DECL_MAX_LOCALS (current_function_decl) + || type_map[index] != TYPE_RETURN_ADDR) + VERIFICATION_ERROR ("invalid ret index"); + + /* The next chunk of code is similar to an inlined version of + * merge_type_state (LABEL_RETURN_LABEL (current_subr)). + * The main differences are that LABEL_RETURN_LABEL is + * pre-allocated by the jsr (but we don't know the size then); + * and that we have to handle TYPE_UNUSED. */ + + if (! RETURN_MAP_ADJUSTED (ret_map)) + { /* First return from this subroutine - fix stack pointer. */ + TREE_VEC_LENGTH (ret_map) = size; + for (index = size; --index >= 0; ) + { + if (TREE_VEC_ELT (ret_map, index) != TYPE_UNUSED) + TREE_VEC_ELT (ret_map, index) = type_map[index]; + } + RETURN_MAP_ADJUSTED (ret_map) = 1; + } + else + { + if (TREE_VEC_LENGTH (ret_map) != size) + VERIFICATION_ERROR ("inconsistent stack size on ret"); + for (index = 0; index < size; index++) + { + tree type = TREE_VEC_ELT (ret_map, index); + if (type != TYPE_UNUSED) + { + type = merge_types (type, type_map [index]); + TREE_VEC_ELT (ret_map, index) = type; + if (type == TYPE_UNKNOWN) + { + if (index >= size - stack_pointer) + VERIFICATION_ERROR + ("inconsistent types on ret from jsr"); + } + else if (TYPE_IS_WIDE (type)) + index++; + } + } + } + + /* Check if there are any more pending blocks in this subroutine. + Because we push pending blocks in a last-in-first-out order, + and because we don't push anything from our caller until we + are done with this subroutine or anything nested in it, + then we are done if the top of the pending_blocks stack is + not in a subroutine, or it is in our caller. */ + if (pending_blocks == NULL_TREE + || ! LABEL_IN_SUBR (pending_blocks) + || LABEL_SUBR_START (pending_blocks) == caller) + { + /* Since we are done with this subroutine (i.e. this is the + last ret from it), set up the (so far known) return + address as pending - with the merged type state. */ + tmp = LABEL_RETURN_LABELS (current_subr); + current_subr = caller; + for ( ; tmp != NULL_TREE; tmp = TREE_CHAIN (tmp)) + { + tree return_label = TREE_VALUE (tmp); + tree return_state = LABEL_TYPE_STATE (return_label); + if (return_state == NULL_TREE) + { + /* This means means we had not verified the + subroutine earlier, so this is the first jsr to + call it. In this case, the type_map of the return + address is just the current type_map - and that + is handled by the following PUSH_PENDING. */ + } + else + { + /* In this case we have to do a merge. But first + restore the type_map for unused slots to those + that were in effect at the jsr. */ + for (index = size; --index >= 0; ) + { + type_map[index] = TREE_VEC_ELT (ret_map, index); + if (type_map[index] == TYPE_UNUSED) + type_map[index] + = TREE_VEC_ELT (return_state, index); + } + } + PUSH_PENDING (return_label); + } + } + } + break; + case OPCODE_jsr_w: + case OPCODE_ret_w: + default: + error ("unknown opcode %d@pc=%d during verification", op_code, PC-1); + return 0; + } + + prevpc = oldpc; + + /* The following test is true if we have entered or exited an exception + handler range *or* we have done a store to a local variable. + In either case we need to consider any exception handlers that + might "follow" this instruction. */ + + if (eh_ranges != prev_eh_ranges) + { + int save_stack_pointer = stack_pointer; + int index = DECL_MAX_LOCALS (current_function_decl); + tree save_type = type_map[index]; + tree save_current_subr = current_subr; + struct eh_range *ranges = find_handler (oldpc); + stack_pointer = 1; + for (; ranges != NULL_EH_RANGE; ranges = ranges->outer) + { + tree chain = ranges->handlers; + + /* We need to determine if the handler is part of current_subr. + The are two cases: (1) The exception catch range + is entirely within current_subr. In that case the handler + is also part of current_subr. + (2) Some of the catch range is not in current_subr. + In that case, the handler is *not* part of current_subr. + + Figuring out which is the case is not necessarily obvious, + in the presence of clever code generators (and obfuscators). + We make a simplifying assumption that in case (2) we + have that the current_subr is entirely within the catch range. + In that case we can assume if that if a caller (the jsr) of + a subroutine is within the catch range, then the handler is + *not* part of the subroutine, and vice versa. */ + + current_subr = save_current_subr; + for ( ; current_subr != NULL_TREE; + current_subr = LABEL_SUBR_CONTEXT (current_subr)) + { + tree return_labels = LABEL_RETURN_LABELS (current_subr); + /* There could be multiple return_labels, but + we only need to check one. */ + int return_pc = LABEL_PC (TREE_VALUE (return_labels)); + if (return_pc <= ranges->start_pc + || return_pc > ranges->end_pc) + break; + } + + for ( ; chain != NULL_TREE; chain = TREE_CHAIN (chain)) + { + tree handler = TREE_VALUE (chain); + tree type = TREE_PURPOSE (chain); + if (type == NULL_TREE) /* a finally handler */ + type = throwable_type_node; + type_map[index] = promote_type (type); + + PUSH_PENDING (handler); + } + } + stack_pointer = save_stack_pointer; + current_subr = save_current_subr; + type_map[index] = save_type; + prev_eh_ranges = eh_ranges; + } + } + return 1; + bad_pc: + message = "program counter out of range"; + goto verify_error; + verify_error: + error ("verification error at PC=%d: %s", oldpc, message); + return 0; +} diff --git a/gcc/java/zextract.c b/gcc/java/zextract.c new file mode 100644 index 00000000000..39bb06c1251 --- /dev/null +++ b/gcc/java/zextract.c @@ -0,0 +1,350 @@ +/* Handle a .class file embedded in a .zip archive. + This extracts a member from a .zip file, but does not handle + uncompression (since that is not needed for classes.zip). + + Copyright (C) 1996 Free Software Foundation, Inc. + +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, 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 GNU CC; 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. */ + +/* Written by Per Bothner , February 1996. */ + +#include "zipfile.h" + + +/* This stuff is partly based on the 28 August 1994 public release of the +Info-ZIP group's portable UnZip zipfile-extraction program (and related +utilities). */ + +#include +#ifdef __STDC__ +#include +#endif +#include /* used in mapname() */ + +/*************/ +/* Defines */ +/*************/ + +#define UNZIP +#define UNZIP_VERSION 20 /* compatible with PKUNZIP 2.0 */ +#define VMS_UNZIP_VERSION 42 /* if OS-needed-to-extract is VMS: can do */ + + +#define ZSUFX ".zip" +#define CENTRAL_HDR_SIG "\113\001\002" /* the infamous "PK" signature */ +#define LOCAL_HDR_SIG "\113\003\004" /* bytes, sans "P" (so unzip */ +#define END_CENTRAL_SIG "\113\005\006" /* executable not mistaken for */ +#define EXTD_LOCAL_SIG "\113\007\010" /* zipfile itself) */ + +#define STORED 0 /* compression methods */ +#define SHRUNK 1 +#define REDUCED1 2 +#define REDUCED2 3 +#define REDUCED3 4 +#define REDUCED4 5 +#define IMPLODED 6 +#define TOKENIZED 7 +#define DEFLATED 8 +#define NUM_METHODS 9 /* index of last method + 1 */ +/* don't forget to update list_files() appropriately if NUM_METHODS changes */ + +#define PK_OK 0 /* no error */ +#define PK_COOL 0 /* no error */ +#define PK_GNARLY 0 /* no error */ +#define PK_WARN 1 /* warning error */ +#define PK_ERR 2 /* error in zipfile */ +#define PK_BADERR 3 /* severe error in zipfile */ +#define PK_MEM 4 /* insufficient memory */ +#define PK_MEM2 5 /* insufficient memory */ +#define PK_MEM3 6 /* insufficient memory */ +#define PK_MEM4 7 /* insufficient memory */ +#define PK_MEM5 8 /* insufficient memory */ +#define PK_NOZIP 9 /* zipfile not found */ +#define PK_PARAM 10 /* bad or illegal parameters specified */ +#define PK_FIND 11 /* no files found */ +#define PK_DISK 50 /* disk full */ +#define PK_EOF 51 /* unexpected EOF */ + +/*--------------------------------------------------------------------------- + True sizes of the various headers, as defined by PKWARE--so it is not + likely that these will ever change. But if they do, make sure both these + defines AND the typedefs below get updated accordingly. + ---------------------------------------------------------------------------*/ +#define LREC_SIZE 26 /* lengths of local file headers, central */ +#define CREC_SIZE 42 /* directory headers, and the end-of- */ +#define ECREC_SIZE 18 /* central-dir record, respectively */ + + +#ifndef SEEK_SET +# define SEEK_SET 0 +# define SEEK_CUR 1 +# define SEEK_END 2 +#endif + +/**************/ +/* Typedefs */ +/**************/ + +typedef char boolean; +typedef unsigned char uch; /* code assumes unsigned bytes; these type- */ +typedef unsigned short ush; /* defs replace byte/UWORD/ULONG (which are */ +typedef unsigned long ulg; /* predefined on some systems) & match zip */ + +/*--------------------------------------------------------------------------- + Zipfile layout declarations. If these headers ever change, make sure the + xxREC_SIZE defines (above) change with them! + ---------------------------------------------------------------------------*/ + + typedef uch local_byte_hdr[ LREC_SIZE ]; +# define L_VERSION_NEEDED_TO_EXTRACT_0 0 +# define L_VERSION_NEEDED_TO_EXTRACT_1 1 +# define L_GENERAL_PURPOSE_BIT_FLAG 2 +# define L_COMPRESSION_METHOD 4 +# define L_LAST_MOD_FILE_TIME 6 +# define L_LAST_MOD_FILE_DATE 8 +# define L_CRC32 10 +# define L_COMPRESSED_SIZE 14 +# define L_UNCOMPRESSED_SIZE 18 +# define L_FILENAME_LENGTH 22 +# define L_EXTRA_FIELD_LENGTH 24 + + typedef uch cdir_byte_hdr[ CREC_SIZE ]; +# define C_VERSION_MADE_BY_0 0 +# define C_VERSION_MADE_BY_1 1 +# define C_VERSION_NEEDED_TO_EXTRACT_0 2 +# define C_VERSION_NEEDED_TO_EXTRACT_1 3 +# define C_GENERAL_PURPOSE_BIT_FLAG 4 +# define C_COMPRESSION_METHOD 6 +# define C_LAST_MOD_FILE_TIME 8 +# define C_LAST_MOD_FILE_DATE 10 +# define C_CRC32 12 +# define C_COMPRESSED_SIZE 16 +# define C_UNCOMPRESSED_SIZE 20 +# define C_FILENAME_LENGTH 24 +# define C_EXTRA_FIELD_LENGTH 26 +# define C_FILE_COMMENT_LENGTH 28 +# define C_DISK_NUMBER_START 30 +# define C_INTERNAL_FILE_ATTRIBUTES 32 +# define C_EXTERNAL_FILE_ATTRIBUTES 34 +# define C_RELATIVE_OFFSET_LOCAL_HEADER 38 + + typedef uch ec_byte_rec[ ECREC_SIZE+4 ]; +/* define SIGNATURE 0 space-holder only */ +# define NUMBER_THIS_DISK 4 +# define NUM_DISK_WITH_START_CENTRAL_DIR 6 +# define NUM_ENTRIES_CENTRL_DIR_THS_DISK 8 +# define TOTAL_ENTRIES_CENTRAL_DIR 10 +# define SIZE_CENTRAL_DIRECTORY 12 +# define OFFSET_START_CENTRAL_DIRECTORY 16 +# define ZIPFILE_COMMENT_LENGTH 20 + + + typedef struct local_file_header { /* LOCAL */ + uch version_needed_to_extract[2]; + ush general_purpose_bit_flag; + ush compression_method; + ush last_mod_file_time; + ush last_mod_file_date; + ulg crc32; + ulg csize; + ulg ucsize; + ush filename_length; + ush extra_field_length; + } local_file_hdr; + + typedef struct central_directory_file_header { /* CENTRAL */ + uch version_made_by[2]; + uch version_needed_to_extract[2]; + ush general_purpose_bit_flag; + ush compression_method; + ush last_mod_file_time; + ush last_mod_file_date; + ulg crc32; + ulg csize; + ulg ucsize; + ush filename_length; + ush extra_field_length; + ush file_comment_length; + ush disk_number_start; + ush internal_file_attributes; + ulg external_file_attributes; + ulg relative_offset_local_header; + } cdir_file_hdr; + + typedef struct end_central_dir_record { /* END CENTRAL */ + ush number_this_disk; + ush num_disk_with_start_central_dir; + ush num_entries_centrl_dir_ths_disk; + ush total_entries_central_dir; + ulg size_central_directory; + ulg offset_start_central_directory; + ush zipfile_comment_length; + } ecdir_rec; + + +/************/ +/* Macros */ +/************/ + +#ifndef MAX +# define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif +#ifndef MIN +# define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + + +/***********************/ +/* Function makeword() */ +/***********************/ + +static ush makeword(b) + uch *b; +{ + /* + * Convert Intel style 'short' integer to non-Intel non-16-bit + * host format. This routine also takes care of byte-ordering. + */ + return (ush)((b[1] << 8) | b[0]); +} + + +/***********************/ +/* Function makelong() */ +/***********************/ + +static ulg makelong(sig) + uch *sig; +{ + /* + * Convert intel style 'long' variable to non-Intel non-16-bit + * host format. This routine also takes care of byte-ordering. + */ + return (((ulg)sig[3]) << 24) + + (((ulg)sig[2]) << 16) + + (((ulg)sig[1]) << 8) + + ((ulg)sig[0]); +} + +int +read_zip_archive (zipf) + register ZipFile *zipf; +{ + int i; + int dir_last_pad; + char *dir_ptr; + char buffer[100]; + + zipf->size = lseek (zipf->fd, 0L, SEEK_END); + + if (zipf->size < (ECREC_SIZE+4) || lseek (zipf->fd, (long)(-(ECREC_SIZE+4)), SEEK_CUR) <= 0) + return -1; + if (read (zipf->fd, buffer, ECREC_SIZE+4) != ECREC_SIZE+4) + return -2; + zipf->count = makeword(&buffer[TOTAL_ENTRIES_CENTRAL_DIR]); + zipf->dir_size = makelong(&buffer[SIZE_CENTRAL_DIRECTORY]); +#define ALLOC malloc + /* Allocate 1 more to allow appending '\0' to last filename. */ + zipf->central_directory = ALLOC (zipf->dir_size+1); + if (lseek (zipf->fd, -(zipf->dir_size+ECREC_SIZE+4), SEEK_CUR) < 0) + return -2; + if (read (zipf->fd, zipf->central_directory, zipf->dir_size) < 0) + return -2; + +#ifdef TEST + printf ("number_this_disk = %d\n", makeword(&buffer[NUMBER_THIS_DISK])); + printf ("num_disk_with_start_central_dir = %d\n", makeword(&buffer[NUM_DISK_WITH_START_CENTRAL_DIR])); + + printf ("num_entries_centrl_dir_ths_disk = %d\n", + makeword(&buffer[NUM_ENTRIES_CENTRL_DIR_THS_DISK])); + printf ("total_entries_central_dir = %d\n", + makeword(&buffer[TOTAL_ENTRIES_CENTRAL_DIR])); + printf ("size_central_directory = %d\n", + makelong(&buffer[SIZE_CENTRAL_DIRECTORY])); + printf ("offset_start_central_directory = %d\n", + makelong(&buffer[OFFSET_START_CENTRAL_DIRECTORY])); + printf ("zipfile_comment_length = %d\n", + makeword(&buffer[ZIPFILE_COMMENT_LENGTH])); +#endif + + dir_last_pad = 0; + dir_ptr = zipf->central_directory; + for (i = 0; i < zipf->count; i++) + { + ZipDirectory *zipd = (ZipDirectory*)(dir_ptr + dir_last_pad); + long uncompressed_size = makelong (&dir_ptr[4+C_UNCOMPRESSED_SIZE]); + long filename_length = makeword (&dir_ptr[4+C_FILENAME_LENGTH]); + long extra_field_length = makeword (&dir_ptr[4+C_EXTRA_FIELD_LENGTH]); + long file_comment_length = makeword (&dir_ptr[4+C_FILE_COMMENT_LENGTH]); + int unpadded_direntry_length; + if ((dir_ptr-zipf->central_directory)+filename_length+CREC_SIZE+4>zipf->dir_size) + return -1; + + zipd->filename_length = filename_length; + zipd->size = uncompressed_size; +#ifdef __GNUC__ +#define DIR_ALIGN __alignof__(ZipDirectory) +#else +#define DIR_ALIGN sizeof(long) +#endif + zipd->filestart = makelong (&dir_ptr[4+C_RELATIVE_OFFSET_LOCAL_HEADER]) + + (LREC_SIZE+4) + filename_length + file_comment_length + + + (extra_field_length ? extra_field_length+4 : 0); + /* About the last term of the expression above. Should the same + apply if file_comment_length is not zero ? I've never seen + the comment field uses so far. FIXME. */ + zipd->filename_offset = CREC_SIZE+4 - dir_last_pad; + unpadded_direntry_length + = zipd->filename_offset + zipd->filename_length + extra_field_length; + zipd->direntry_size = + ((unpadded_direntry_length + DIR_ALIGN) / DIR_ALIGN) * DIR_ALIGN; + dir_last_pad = zipd->direntry_size - unpadded_direntry_length; + dir_ptr = (char*)zipd + unpadded_direntry_length; + *dir_ptr = '\0'; + } + return 0; +} + +#ifdef TEST +main () +{ + ZipFile zipf[1]; + ZipDirectory *zipd; + int i; + + zipf->fd = 0; + + i = read_zip_archive (zipf); + if (i) + { + fprintf (stderr, "Bad zip file.\n"); + exit (i); + } + + zipd = (ZipDirectory*) zipf->central_directory; + for (i = 0; i < zipf->count; i++, zipd = ZIPDIR_NEXT (zipd)) + { + printf ("%d: size:%d, name(#%d)%s, offset:%d\n", + i, zipd->size, zipd->filename_length, + ZIPDIR_FILENAME (zipd), + zipd->filestart); + } +} +#endif diff --git a/gcc/java/zipfile.h b/gcc/java/zipfile.h new file mode 100644 index 00000000000..5d71184139b --- /dev/null +++ b/gcc/java/zipfile.h @@ -0,0 +1,58 @@ +/* Definitions for using a zipped' archive. + + Copyright (C) 1996 Free Software Foundation, Inc. + +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, 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 GNU CC; 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. */ + +struct ZipFile { + int fd; + long size; + long count; + long dir_size; + char *central_directory; +}; + +typedef struct ZipFile ZipFile; + +struct ZipDirectory { + int direntry_size; + int filename_offset; + long size; /* length of file */ + long filestart; /* start of file in archive */ + long filename_length; + /* char mid_padding[...]; */ + /* char filename[filename_length]; */ + /* char end_padding[...]; */ +}; + +typedef struct ZipDirectory ZipDirectory; + +struct ZipFileCache { + struct ZipFile z; + struct ZipFileCache *next; + char *name; +}; + +extern struct ZipFileCache *SeenZipFiles; + +#define ZIPDIR_FILENAME(ZIPD) ((char*)(ZIPD)+(ZIPD)->filename_offset) +#define ZIPDIR_NEXT(ZIPD) \ + ((ZipDirectory*)((char*)(ZIPD)+(ZIPD)->direntry_size)) +#define ZIPMAGIC 0x504b0304 -- 2.11.4.GIT