first commit

This commit is contained in:
Jeena Paradies 2011-04-19 11:37:05 +02:00
commit 063194f8be
349 changed files with 36508 additions and 0 deletions

BIN
jasmin/jasmin-2.4.zip Normal file

Binary file not shown.

View file

@ -0,0 +1,116 @@
Jasmin README file 1 March 1997, Jonathan Meyer
Last updated October 2004
Introduction
------------
Welcome to Jasmin version 1.1.
Jasmin is a Java Assembler Interface. It takes ASCII descriptions for Java
classes, written in a simple assembler-like syntax, using the Java
Virtual Machine instruction set. It converts them into binary Java class
files suitable for loading into a Java interpreter.
Jasmin was originally written as the companion to the
book "Java Virtual Machine", published by O'Reilly, written by
Jon Meyer and Troy Downing. (See http://www.ora.com/catalog/javavm/).
The book is now out of print. However, the Jasmin assembler retains its
usefulness as a utility, and continues its life as an OpenSource project.
Background
----------
Jasmin is today a little long in the tooth. It was originally coded in
1996 as a stop-gap until Sun released their own assembler. It has seen
no major upgrades since 1997. By 2004 Sun still has not released an
official assembler, so I decided to release Jasmin as a sourceforge
project. Hopefully this will inject some fresh life into the project...
Home Page
---------
Check out the Jasmin home page at:
http://jasmin.sourceforge.net
Requirements
------------
Jasmin is written in Java, and should work with most Java 1.1 environments.
To run Jasmin you need to have a Java 2 Runtime Environment available (e.g. JDK 1.4).
This can be downloaded from "http://www.javasoft.com/j2se/".
Getting Started
---------------
The Jasmin distribution contains a jasmin.jar file holding the Jasmin assembler.
To run Jasmin, execute the Jarfile, specifying any files to assemble
as command-line parameters, e.g. to assemble the "HelloWorld.j" file in examples,
first use cd to change into the Jasmin directory:
cd c:\jasmin-1.1 [Windows]
or
cd ~/jasmin-1.1 [Unix]
Then, to run Jasmin, use:
java -jar jasmin.jar examples\HelloWorld.j [Windows]
or
java -jar jasmin.jar examples/HelloWorld.j [Unix/MacOsX]
After running Jasmin as above, it generates a compiled HelloWorld.class file
in the examples directory.
You can then run the HelloWorld program by doing:
java examples.HelloWorld
Build Instructions
------------------
Jasmin uses Ant as its build mechanism. See build.xml for instructions on how
to build Jasmin. In brief, you need to:
1. Start a Terminal or Command window.
2. Change (cd) into the Jasmin directory
3. Make sure that java, javac etc. are on your path
4. Run build.bat (Windows) or build.sh (Unix).
For example, on Windows, this might look something like:
cd c:\jasmin-1.1 # change to Jasmin directory
build all
Or, for Unix, it might be like:
cd ~/jasmin-1.1 # change to Jasmin directory
./build.sh all
These scripts use the build.xml configuration file to specify build parameters.
Where Next
----------
After trying Jasmin out, have a look at the HelloWorld.j source in the examples directory,
try compiling and running the other examples.
There is documentation for Jasmin in the doc directory. You should probably
start with the 'guide.html' document.
Files
-----
The following files are included in this distribution:
README.txt - this file
jasmin.jar - executable Jar file containing Jasmin assembler
examples/ - directory containing example files written for Jasmin
src/ - the Java source code and for the jasmin package
lib/ - Contains Java sources for the java_cup and jas packages
docs/ - various documentation files.
Copyright
---------
Jasmin is Copyright (1997-2004) Jonathan Meyer, under the terms of
the GNU General Public License. See license-jasmin.txt for more.
Jasmin uses the JAS package which has its own copyright - see lib/jas/README.
[sbktech.org no longer seem to be in existence, but the code lives
on in this project].
Jasmin utilizes Scott E. Hudson's Java Cup package v0.9e, which is also in
the lib directory. See http://www.cs.princeton.edu/~appel/modern/java/CUP/

107
jasmin/jasmin-2.4/build.bat Normal file
View file

@ -0,0 +1,107 @@
@echo off
REM Copyright 2001,2004 The Apache Software Foundation
REM
REM Licensed under the Apache License, Version 2.0 (the "License");
REM you may not use this file except in compliance with the License.
REM You may obtain a copy of the License at
REM
REM http://www.apache.org/licenses/LICENSE-2.0
REM
REM Unless required by applicable law or agreed to in writing, software
REM distributed under the License is distributed on an "AS IS" BASIS,
REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
REM See the License for the specific language governing permissions and
REM limitations under the License.
if exist "%HOME%\antrc_pre.bat" call "%HOME%\antrc_pre.bat"
if "%OS%"=="Windows_NT" @setlocal
rem %~dp0 is expanded pathname of the current script under NT
set ANT_HOME=.
rem set DEFAULT_ANT_HOME=%~dp0..
if "%ANT_HOME%"=="" set ANT_HOME=%DEFAULT_ANT_HOME%
set DEFAULT_ANT_HOME=
rem Slurp the command line arguments. This loop allows for an unlimited number
rem of arguments (up to the command line limit, anyway).
set ANT_CMD_LINE_ARGS=%1
if ""%1""=="""" goto doneStart
shift
:setupArgs
if ""%1""=="""" goto doneStart
set ANT_CMD_LINE_ARGS=%ANT_CMD_LINE_ARGS% %1
shift
goto setupArgs
rem This label provides a place for the argument list loop to break out
rem and for NT handling to skip to.
:doneStart
rem find ANT_HOME if it does not exist due to either an invalid value passed
rem by the user or the %0 problem on Windows 9x
if exist "%ANT_HOME%\lib\ant.jar" goto checkJava
rem check for ant in Program Files
if not exist "%ProgramFiles%\ant" goto checkSystemDrive
set ANT_HOME=%ProgramFiles%\ant
goto checkJava
:checkSystemDrive
rem check for ant in root directory of system drive
if not exist %SystemDrive%\ant\lib\ant.jar goto checkCDrive
set ANT_HOME=%SystemDrive%\ant
goto checkJava
:checkCDrive
rem check for ant in C:\ant for Win9X users
if not exist C:\ant\lib\ant.jar goto noAntHome
set ANT_HOME=C:\ant
goto checkJava
:noAntHome
echo ANT_HOME is set incorrectly or ant could not be located. Please set ANT_HOME.
goto end
:checkJava
set _JAVACMD=%JAVACMD%
if "%JAVA_HOME%" == "" goto noJavaHome
if not exist "%JAVA_HOME%\bin\java.exe" goto noJavaHome
if "%_JAVACMD%" == "" set _JAVACMD=%JAVA_HOME%\bin\java.exe
goto checkJikes
:noJavaHome
if "%_JAVACMD%" == "" set _JAVACMD=java.exe
:checkJikes
if not "%JIKESPATH%"=="" goto runAntWithJikes
:runAnt
if not "%CLASSPATH%"=="" goto runAntWithClasspath
"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% %ANT_CMD_LINE_ARGS%
goto end
:runAntWithClasspath
"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% -lib "%CLASSPATH%" %ANT_CMD_LINE_ARGS%
goto end
:runAntWithJikes
if not "%CLASSPATH%"=="" goto runAntWithJikesAndClasspath
"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" "-Djikes.class.path=%JIKESPATH%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% %ANT_CMD_LINE_ARGS%
goto end
:runAntWithJikesAndClasspath
"%_JAVACMD%" %ANT_OPTS% -classpath "%ANT_HOME%\lib\ant-launcher.jar" "-Dant.home=%ANT_HOME%" "-Djikes.class.path=%JIKESPATH%" org.apache.tools.ant.launch.Launcher %ANT_ARGS% -lib "%CLASSPATH%" %ANT_CMD_LINE_ARGS%
goto end
:end
set _JAVACMD=
set ANT_CMD_LINE_ARGS=
if "%OS%"=="Windows_NT" @endlocal
:mainEnd
if exist "%HOME%\antrc_post.bat" call "%HOME%\antrc_post.bat"

305
jasmin/jasmin-2.4/build.sh Normal file
View file

@ -0,0 +1,305 @@
#! /bin/sh
# Copyright 2001-2004 The Apache Software Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
ANT_HOME=.
export ANT_HOME
# Extract launch and ant arguments, (see details below).
ant_exec_args=
no_config=false
use_jikes_default=false
ant_exec_debug=false
show_help=false
for arg in "$@" ; do
if [ "$arg" = "--noconfig" ] ; then
no_config=true
elif [ "$arg" = "--usejikes" ] ; then
use_jikes_default=true
elif [ "$arg" = "--execdebug" ] ; then
ant_exec_debug=true
elif [ my"$arg" = my"--h" -o my"$arg" = my"--help" ] ; then
show_help=true
ant_exec_args="$ant_exec_args -h"
else
if [ my"$arg" = my"-h" -o my"$arg" = my"-help" ] ; then
show_help=true
fi
ant_exec_args="$ant_exec_args \"$arg\""
fi
done
# Source/default ant configuration
if $no_config ; then
rpm_mode=false
usejikes=$use_jikes_default
else
# load system-wide ant configuration
if [ -f "/etc/ant.conf" ] ; then
. /etc/ant.conf
fi
# load user ant configuration
if [ -f "$HOME/.ant/ant.conf" ] ; then
. $HOME/.ant/ant.conf
fi
if [ -f "$HOME/.antrc" ] ; then
. "$HOME/.antrc"
fi
# provide default configuration values
if [ -z "$rpm_mode" ] ; then
rpm_mode=false
fi
if [ -z "$usejikes" ] ; then
usejikes=$use_jikes_default
fi
fi
# Setup Java environment in rpm mode
if $rpm_mode ; then
if [ -f /usr/share/java-utils/java-functions ] ; then
. /usr/share/java-utils/java-functions
set_jvm
set_javacmd
fi
fi
# OS specific support. $var _must_ be set to either true or false.
cygwin=false;
darwin=false;
case "`uname`" in
CYGWIN*) cygwin=true ;;
Darwin*) darwin=true
if [ -z "$JAVA_HOME" ] ; then
JAVA_HOME=/System/Library/Frameworks/JavaVM.framework/Home
fi
;;
esac
if [ -z "$ANT_HOME" -o ! -d "$ANT_HOME" ] ; then
# try to find ANT
if [ -d /opt/ant ] ; then
ANT_HOME=/opt/ant
fi
if [ -d "${HOME}/opt/ant" ] ; then
ANT_HOME="${HOME}/opt/ant"
fi
## resolve links - $0 may be a link to ant's home
PRG="$0"
progname=`basename "$0"`
# need this for relative symlinks
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
ANT_HOME=`dirname "$PRG"`/..
# make it fully qualified
ANT_HOME=`cd "$ANT_HOME" && pwd`
fi
# For Cygwin, ensure paths are in UNIX format before anything is touched
if $cygwin ; then
[ -n "$ANT_HOME" ] &&
ANT_HOME=`cygpath --unix "$ANT_HOME"`
[ -n "$JAVA_HOME" ] &&
JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
fi
# set ANT_LIB location
ANT_LIB="${ANT_HOME}/lib"
if [ -z "$JAVACMD" ] ; then
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
else
JAVACMD=`which java 2> /dev/null `
if [ -z "$JAVACMD" ] ; then
JAVACMD=java
fi
fi
fi
if [ ! -x "$JAVACMD" ] ; then
echo "Error: JAVA_HOME is not defined correctly."
echo " We cannot execute $JAVACMD"
exit 1
fi
# Build local classpath using just the launcher in non-rpm mode or
# use the Jpackage helper in rpm mode with basic and default jars
# specified in the ant.conf configuration. Because the launcher is
# used, libraries linked in ANT_HOME will also be include, but this
# is discouraged as it is not java-version safe. A user should
# request optional jars and their dependencies via the OPT_JAR_LIST
# variable
if $rpm_mode && [ -f /usr/bin/build-classpath ] ; then
LOCALCLASSPATH="$(/usr/bin/build-classpath ant ant-launcher jaxp_parser_impl xml-commons-apis)"
# If the user requested to try to add some other jars to the classpath
if [ -n "$OPT_JAR_LIST" ] ; then
_OPTCLASSPATH="$(/usr/bin/build-classpath $OPT_JAR_LIST 2> /dev/null)"
if [ -n "$_OPTCLASSPATH" ] ; then
LOCALCLASSPATH="$LOCALCLASSPATH:$_OPTCLASSPATH"
fi
fi
# Explicitly add javac path to classpath, assume JAVA_HOME set
# properly in rpm mode
if [ -f "$JAVA_HOME/lib/tools.jar" ] ; then
LOCALCLASSPATH="$LOCALCLASSPATH:$JAVA_HOME/lib/tools.jar"
fi
if [ -f "$JAVA_HOME/lib/classes.zip" ] ; then
LOCALCLASSPATH="$LOCALCLASSPATH:$JAVA_HOME/lib/classes.zip"
fi
# if CLASSPATH_OVERRIDE env var is set, LOCALCLASSPATH will be
# user CLASSPATH first and ant-found jars after.
# In that case, the user CLASSPATH will override ant-found jars
#
# if CLASSPATH_OVERRIDE is not set, we'll have the normal behaviour
# with ant-found jars first and user CLASSPATH after
if [ -n "$CLASSPATH" ] ; then
# merge local and specified classpath
if [ -z "$LOCALCLASSPATH" ] ; then
LOCALCLASSPATH="$CLASSPATH"
elif [ -n "$CLASSPATH_OVERRIDE" ] ; then
LOCALCLASSPATH="$CLASSPATH:$LOCALCLASSPATH"
else
LOCALCLASSPATH="$LOCALCLASSPATH:$CLASSPATH"
fi
# remove class path from launcher -lib option
CLASSPATH=""
fi
else
# not using rpm_mode; use launcher to determine classpaths
if [ -z "$LOCALCLASSPATH" ] ; then
LOCALCLASSPATH=$ANT_LIB/ant-launcher.jar
else
LOCALCLASSPATH=$ANT_LIB/ant-launcher.jar:$LOCALCLASSPATH
fi
fi
if [ -n "$JAVA_HOME" ] ; then
# OSX hack to make Ant work with jikes
if $darwin ; then
OSXHACK="${JAVA_HOME}/../Classes"
if [ -d "${OSXHACK}" ] ; then
for i in "${OSXHACK}"/*.jar
do
JIKESPATH="$JIKESPATH:$i"
done
fi
fi
fi
# Allow Jikes support (off by default)
if $usejikes; then
ANT_OPTS="$ANT_OPTS -Dbuild.compiler=jikes"
fi
# For Cygwin, switch paths to appropriate format before running java
if $cygwin; then
if [ "$OS" = "Windows_NT" ] && cygpath -m .>/dev/null 2>/dev/null ; then
format=mixed
else
format=windows
fi
ANT_HOME=`cygpath --$format "$ANT_HOME"`
ANT_LIB=`cygpath --$format "$ANT_LIB"`
JAVA_HOME=`cygpath --$format "$JAVA_HOME"`
LOCALCLASSPATH=`cygpath --path --$format "$LOCALCLASSPATH"`
if [ -n "$CLASSPATH" ] ; then
CLASSPATH=`cygpath --path --$format "$CLASSPATH"`
fi
CYGHOME=`cygpath --$format "$HOME"`
fi
# Show script help if requested
if $show_help ; then
echo $0 '[script options] [options] [target [target2 [target3] ..]]'
echo 'Script Options:'
echo ' --help, --h print this message and ant help'
echo ' --noconfig suppress sourcing of /etc/ant.conf,'
echo ' $HOME/.ant/ant.conf, and $HOME/.antrc'
echo ' configuration files'
echo ' --usejikes enable use of jikes by default, unless'
echo ' set explicitly in configuration files'
echo ' --execdebug print ant exec line generated by this'
echo ' launch script'
echo ' '
fi
# add a second backslash to variables terminated by a backslash under cygwin
if $cygwin; then
case "$ANT_HOME" in
*\\ )
ANT_HOME="$ANT_HOME\\"
;;
esac
case "$CYGHOME" in
*\\ )
CYGHOME="$CYGHOME\\"
;;
esac
case "$JIKESPATH" in
*\\ )
JIKESPATH="$JIKESPATH\\"
;;
esac
case "$LOCALCLASSPATH" in
*\\ )
LOCALCLASSPATH="$LOCALCLASSPATH\\"
;;
esac
case "$CLASSPATH" in
*\\ )
CLASSPATH="$CLASSPATH\\"
;;
esac
fi
# Execute ant using eval/exec to preserve spaces in paths,
# java options, and ant args
ant_sys_opts=
if [ -n "$CYGHOME" ]; then
if [ -n "$JIKESPATH" ]; then
ant_sys_opts="-Djikes.class.path=\"$JIKESPATH\" -Dcygwin.user.home=\"$CYGHOME\""
else
ant_sys_opts="-Dcygwin.user.home=\"$CYGHOME\""
fi
else
if [ -n "$JIKESPATH" ]; then
ant_sys_opts="-Djikes.class.path=\"$JIKESPATH\""
fi
fi
ant_exec_command="exec \"$JAVACMD\" $ANT_OPTS -classpath \"$LOCALCLASSPATH\" -Dant.home=\"$ANT_HOME\" -Dant.library.dir=\"$ANT_LIB\" $ant_sys_opts org.apache.tools.ant.launch.Launcher $ANT_ARGS -lib \"$CLASSPATH\" $ant_exec_args"
if $ant_exec_debug ; then
echo $ant_exec_command
fi
eval $ant_exec_command

297
jasmin/jasmin-2.4/build.xml Normal file
View file

@ -0,0 +1,297 @@
<!-- ===========================================================================
Installing the build tools
==========================
The Jasmin build system is based on Jakarta Ant, which is a Java building tool
originally developed for the Jakarta Tomcat project but now used in many other
Apache projects and extended by many developers.
Ant is a little but very handy tool that uses a build file written in XML
(this file) as building instructions. For more information refer to
"http://jakarta.apache.org/ant/".
Jasmin includes its own copy of the ant library in the lib directory.
The only other thing that you have to make sure of is that the
"JAVA_HOME" environment property is set to match the top level directory
containing the JVM you want to use. For example:
C:\> set JAVA_HOME=C:\jdk1.4
or on Unix:
% setenv JAVA_HOME /usr/local/java
(csh)
> JAVA_HOME=/usr/java; export JAVA_HOME
(ksh, bash)
That's it!
Building instructions
=====================
First, make sure your current working directory is
where this very file is located. Then type:
./build.sh all (unix)
build.bat all (win32)
To build the framework, examples, and tests or:
./build.sh (unix)
build.bat (win32)
To list all the possible build targets.
If everything is right (see *) and all the required packages are visible, this action
will generate a build directory ./build, containing the jar file:
jasmin.jar - This jar contains the Jasmin assembler
This jar file can be run by the command
java -jar jasmin.jar <filenames>
from within the ./build directory.
* On Win/98 you may get an "Out of Environment Space" error message. This happens if
Windows provides too small a space for environment variables. To work around this
limitation:
Close the DOS window (the error can corrupt its CLASSPATH variable).
Open a new DOS window. Click on the MS-DOS icon at the top left of the window.
Select the Properties option.
Click on the Memory tab.
Adjust the "Initial Environment" drop-down box from "Auto" to "2816".
Click OK.
Then try building.
-->
<project name="Jasmin" default="usage" basedir=".">
<!-- =================================================================== -->
<!-- Initialization target -->
<!-- =================================================================== -->
<target name="init">
<tstamp/>
<property name="Name" value="Jasmin"/>
<property name="name" value="jasmin"/>
<property name="version" value="2.1"/>
<property name="year" value="2006"/>
<echo message="----------- ${Name} ${version} [${year}] ------------"/>
<property name="build.compiler" value="modern"/>
<property name="debug" value="on"/>
<property name="optimize" value="on"/>
<property name="deprecation" value="on"/>
<property name="packages" value="jasmin.*,jas.*,scm.*"/>
<!-- Define the source directories -->
<property name="root.dir" value="./"/>
<property name="docs.dir" value="${root.dir}/docs"/>
<property name="lib.dir" value="${root.dir}/lib"/>
<property name="src.dir" value="${root.dir}/src"/>
<!-- Define the source build directories -->
<property name="build.dir" value="${root.dir}/build"/>
<property name="build.lib" value="${build.dir}/lib"/>
<property name="build.jasmin.src" value="${build.dir}/jasmin/src"/>
<property name="build.jasmin.dest" value="${build.dir}/jasmin/classes"/>
<property name="apidocs.dir" value="${docs.dir}/api"/>
<!-- Define the distribution directories -->
<property name="dist.root" value="${root.dir}/dist"/>
<property name="sourcedist.dir" value="${dist.root}/${name}-${version}/${name}-${version}"/>
<property name="compiledist.dir" value="${dist.root}/${name}-${version}/${name}-${version}"/>
</target>
<!-- =================================================================== -->
<!-- Help on usage -->
<!-- =================================================================== -->
<target name="usage">
<echo message=""/>
<echo message=""/>
<echo message="Jasmin Build file"/>
<echo message="-------------------------------------------------------------"/>
<echo message=""/>
<echo message=" available targets are:"/>
<echo message=""/>
<echo message=" all --> builds all the jars in ./build"/>
<echo message=" parser --> regenerates parser.java from parser.cup "/>
<echo message=" docs --> builds the documentation in ./docs/api"/>
<echo message=" clean --> restores distribution to original state"/>
<echo message=" sourcedist --> builds and zips the source distribution"/>
<echo message=" usage --> (default) displays build menu"/>
<echo message=""/>
<echo message=" See the comments inside the build.xml file for more details."/>
<echo message="-------------------------------------------------------------"/>
<echo message=""/>
<echo message=""/>
</target>
<!-- =================================================================== -->
<!-- Prepares the build directory -->
<!-- =================================================================== -->
<target name="prepare" depends="init">
<mkdir dir="${build.dir}"/>
<mkdir dir="${build.lib}"/>
<copy todir="${build.lib}">
<fileset dir="${lib.dir}"/>
</copy>
</target>
<!-- =================================================================== -->
<!-- Prepares the jasmin source code -->
<!-- =================================================================== -->
<target name="prepare-jasmin" depends="prepare">
<mkdir dir="${build.jasmin.src}"/>
<mkdir dir="${build.jasmin.dest}"/>
<copy todir="${build.jasmin.src}">
<fileset dir="${src.dir}"/>
</copy>
</target>
<!-- =================================================================== -->
<!-- Compiles the jasmin source code -->
<!-- =================================================================== -->
<target name="compile-jasmin" depends="prepare-jasmin">
<javac srcdir="${build.jasmin.src}"
source="1.4"
destdir="${build.jasmin.dest}"
debug="${debug}"
deprecation="${deprecation}"
optimize="${optimize}"/>
</target>
<!-- =================================================================== -->
<!-- Creates the jasmin.jar in ./build -->
<!-- =================================================================== -->
<target name="jasmin" depends="compile-jasmin">
<jar jarfile="${root.dir}/${name}.jar"
basedir="${build.jasmin.dest}"
manifest="${build.jasmin.src}/jasmin.mf"
includes="jasmin/*.class,jas/*.class,java_cup/runtime/*.class"/>
</target>
<!-- =================================================================== -->
<!-- Compiles the JavaCup library -->
<!-- =================================================================== -->
<target name="compile-java_cup" depends="prepare-jasmin">
<mkdir dir="${build.jasmin.dest}/java_cup"/>
<javac srcdir="${build.jasmin.src}/java_cup"
source="1.4"
destdir="${build.jasmin.dest}/java_cup"
debug="${debug}"
deprecation="${deprecation}"
optimize="${optimize}"/>
</target>
<target name="java_cup" depends="compile-java_cup">
<jar jarfile="${root.dir}/lib/java_cup.jar"
basedir="${build.jasmin.dest}"
includes="java_cup/*.class,java_cup/runtime/*.class"/>
</target>
<!--
This task runs Java Cup to generate the Jasmin Parser (parser.java)
from the CUP file (parser.cup) in the Jasmin src directory. You only need to
run this task if you edit parser.cup.
-->
<target name="parser" depends="java_cup">
<java classname="java_cup.Main" output="test.java" input="src/jasmin/parser.cup">
<classpath>
<pathelement location="${root.dir}/lib/java_cup.jar"/>
</classpath>
</java>
<move file="parser.java" tofile="src/jasmin/parser.java"/>
<move file="sym.java" tofile="src/jasmin/sym.java"/>
</target>
<!-- =================================================================== -->
<!-- Build all jars in ./build -->
<!-- =================================================================== -->
<target name="all" depends="jasmin,docs"/>
<!-- =================================================================== -->
<!-- Creates the API documentation in ./docs/api/ -->
<!-- =================================================================== -->
<target name="docs">
<mkdir dir="${apidocs.dir}"/>
<javadoc packagenames="${packages}"
link="http://java.sun.com/j2se/1.4/docs/api"
sourcepath="${src.dir}"
destdir="${apidocs.dir}"
author="true"
additionalparam="-source 1.4"
version="true"
use="true"
splitindex="true"
noindex="false"
windowtitle="${Name} API"
doctitle="${Name}"
bottom="Copyright &#169; ${year} Jonathan Meyer, USA All rights reserved."
/>
</target>
<!-- =================================================================== -->
<!-- Build source distribution in ./dist -->
<!-- =================================================================== -->
<target name="sourcedist" depends="clean">
<mkdir dir="${dist.root}"/>
<mkdir dir="${sourcedist.dir}"/>
<copy todir="${sourcedist.dir}">
<fileset dir="${root.dir}"/>
</copy>
<!-- Now delete what we dont want, probably a better way to do this -->
<delete dir="${sourcedist.dir}/dist"/>
<delete dir="${sourcedist.dir}/classes"/>
<zip zipfile="${dist.root}/${name}-${version}.zip"
basedir="${dist.root}/${name}-${version}"
whenempty="create"
/>
</target>
<!-- =================================================================== -->
<!-- Build compiled distribution in ./dist -->
<!-- =================================================================== -->
<target name="compiledist" depends="clean, all">
<mkdir dir="${dist.root}"/>
<mkdir dir="${compiledist.dir}"/>
<copy todir="${compiledist.dir}">
<fileset dir="${root.dir}"/>
</copy>
<!-- Now delete what we dont want, probably a better way to do this -->
<delete dir="${compiledist.dir}/dist"/>
<delete dir="${compiledist.dir}/build"/>
<zip zipfile="${dist.root}/${name}-${version}.zip"
basedir="${dist.root}/${name}-${version}"
whenempty="create"
/>
</target>
<!-- =================================================================== -->
<!-- Clean restores distribution to original state -->
<!-- =================================================================== -->
<target name="clean" depends="init">
<delete dir="${build.dir}"/>
<delete dir="${dist.root}"/>
<delete dir="${apidocs.dir}"/>
</target>
</project>
<!-- End of file -->

View file

@ -0,0 +1,114 @@
Jasmin Revision History Jonathan Meyer
15 Oct 2004 - Release 1.1
* Switched to Ant Build System
* Moved java_cup and jas sources into src directory
* Updated documentation to use style sheets
* Changed docs to reflect using jar files rather than class files
* Uploaded to SourceForge
-----------------------------------------------------------------------------
11 Apr 97 - Release 1.06.
11 Apr 97
* Fixed bug which prevented the source name from being written out
in the class file
* Improved README file
2 Mar 97 - Release 1.05.
1 Mar 97
* Moved scripts into a bin directory.
* Added support for Visual J++.
Added vjasmin.bat, for running Jasmin using Visual J++.
Converted JAS/Jasmin to use its own internal RuntimeConstants, so that
there is no longer any dependency on Sun's version (needed by J++).
* Tidied API:
Renamed "Jasmin" class "ClassFile" (sorry to those of you using the API
from 1.04). The ClassFile class is documented in the doc/api directory.
* Mods for Java 1.1:
Classes now set the ACC_SUPER bit in their access flags.
i2b/i2s/i2c are now synonyms for int2byte, int2short, int2char.
invokespecial is now a synonym for invokenonvirtual.
* Mods to pick up documentation in book:
"wide" is now a recognized instruction in Jasmin files - although the assembler
just ignores it!
Added the optional <high> parameter to tableswitch.
* Fixed bug in .catch all
10 Feb 96 - Release 1.04.
8 Feb 97
* Updated to use latest version of JAS. This fixes some bugs in the
earlier release (including handling of _w instructions)
* Split several of the internal classes into smaller pieces.
* Restructured internal sources so that Jasmin, Scanner and parser
no longer rely on static data structures. Now there is a public API
to Jasmin, for people that want to assemble classes using their own
data input/output streams.
30 Oct 96
* Added support for more \ escapes in quoted strings. In
particular, you can now use \nnn to specify a character using
octal.
2 Oct 96 - Release 1.03.
1 Oct 96
* Added better support for interfaces: added the .interface
directive (an alternative to the .class directive), and also a
.implements directive. Updates guide.html to mention these new
features.
24 Sept 96
* Fixed several problems with guide.html - thanks to feedback from
Shawn Silverman (umsilve1@cc.umanitoba.ca).
23 Aug 96
* Tidied up documentation and implementation for wide instructions.
Now ldc and ldc_w are used for single-word items, whereas
ldc2_w is used for two word items (previously, I had ldc_w as
a synonym for ldc2_w - oops).
25 July 96
* Added documentation for .var directive.
* Fixed line numbering produced by -g flag (I hope).
* Improved error reporting slightly.
24 July 96
* Added fix to scanner to handle Ctrl-M characters,
for DOS/NT Systems. (Thanks sbk!)
18 July 96 - Release 1.0.

View file

@ -0,0 +1,182 @@
<html>
<head>
<title>About Jasmin</title>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
<table>
<tr><td width=550>
<center>
<p><img src=jasmin_icon.jpg></p>
<p>
<div class="h1">ABOUT JASMIN</div>
Jonathan Meyer, July 1996
</p>
</center>
<h1>Introduction</h1>
This document tries to answer some questions you might have
about Jasmin. In particular, several people have asked me what
Jasmin is, why they might use Jasmin, and why I wrote it in the
first place. I've tried to give some answers to these questions
below.<p>
<h1>Jasmin Assembler</h1>
Jasmin is a Java Assembler Interface. It takes ASCII descriptions for Java
classes, written in a simple assembler-like syntax using the Java Virtual
Machine instructions set. It converts them into binary Java class files
suitable for loading into a Java interpreter.<p>
To give you a flavor, here is the Jasmin assembly code for HelloWorld:<p>
<pre>
.class public HelloWorld
.super java/lang/Object
;
; standard initializer (calls java.lang.Object's initializer)
;
.method public &lt;init&gt;()V
aload_0
invokenonvirtual java/lang/Object/&lt;init&gt;()V
return
.end method
;
; main() - prints out Hello World
;
.method public static main([Ljava/lang/String;)V
.limit stack 2 ; up to two items can be pushed
; push System.out onto the stack
getstatic java/lang/System/out Ljava/io/PrintStream;
; push a string onto the stack
ldc "Hello World!"
; call the PrintStream.println() method.
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
; done
return
.end method
</pre>
<p>
Jasmin was originally created as a companion to the book "Java Virtual Machine",
written by Jon Meyer and Troy Downing and published by O'Reilly Associates. The
book is now out of print. Jasmin survives as a SourceForge Open Source project.
</p>
<h1>Motivation for Jasmin</h1>
<p>
Jasmin was written because, at the time that we wrote the Java Virtual Machine
book for O'Reilly, Sun had not published an assembler format for the
Java virtual machine.
</p>
<p>
Generating a binary Java .class file is pretty fiddly. Its like
creating an a.out (or .exe) file by hand. Even using a Java package like
JAS (a Java API for creating class files, used internally by Jasmin and written by KB Sriram), you
need to know a lot about the philosophy of the Java Virtual
Machine before you can write something at the Virtual
Machine level and generate a Java class. <p>
We wanted something that made it very easy for a student or programmer
to explore the Java Virtual Machine, or write a new language
which targets the VM, without getting into the details of constant
pool indices, attribute tables, and so on.<p>
<p>
Creating a Java assembler seemed like a good solution.
</p>
<p>
Unfortunately, Sun has not seen the need to define a standard Java
assembler format, and has not released tools perform Java assembly.
</p>
<p>Sun does provide a javap program which can print the assembly code
in a class file. However, the javap output is inappropriate for
use as an assembler format. It is designed to be read by a person,
not to be parsed by an assembler, so it has a number of
omissions and drawbacks. </p>
<p>
Internally, Sun has a Java assembler tool. In hindsight, the syntax used by their internal tool is nicer than
the Jasmin syntax. However, to my knowledge, their tool is still not widely available, nor is it a formally
supported part of the Sun JDK.
</p>
<h1>Update on Jasmin Today (2004) </h1>
Since Jasmin was written, it has become the de-facto standard assembly format for Java. It is used in dozens of compiler classes throughout the world, and has
been ported and cloned multiple times. For better or worse, Jasmin remains the original Java assembler.
<p>
[As an interesting comparison, Microsoft .NET shipped out-of-box with an
assembler, a disassembler, a standard IL assembly format, and built-in libraries
for code-genning (generating classes on the fly). It would be great if Sun was
as comprehensive in their support of the JVM].
</p>
<h1>What can I do with Jasmin?</h1>
To give you some ideas, below are some theoretical Jasmin users/uses.<p>
<h3>Teachers</h3>
If you are teaching a compilers course, you could have students
write a compiler which generates Jasmin assembly files,
and then assembles those files into Java class files. Then you
can integrate the advantages of the Virtual Machine (portability,
the verifier, an object model...) into your courseware.<p>
<h3>Hobbyists</h3>
Jasmin lets you poke around in Java at the VM level, so that
you can gain a real understanding of how Java works and
what the Virtual Machine is like.<p>
<h3>System Implementors</h3>
If you are implementing a Java runtime system, Jasmin is
an essential tool for generating test classes.<p>
<h3>Advanced Programmers</h3>
You could use Jasmin to write a critical class or method by
hand (e.g. if you think that Java isn't doing things
as well as it could). <p>
Alternatively, you could create a syntax extension to the
Java language which uses Jasmin (or JAS). <p>
<h3>Language Implementors</h3>
If you want to create an implementation of your
favorite programming language which targets the
Virtual Machine, Jasmin may be a simpler approach than
writing a Java class file generator. This is especially
true if your compiler is implemented in something other
than Java, since you can create Java class files easily
without having to get involved in the details of the
binary file format.<p>
<h3>Security Wizards</h3>
Sun's claim that the Java class verifier protects you from
hostile programs is a pretty strong one. Jasmin lets you create
'hostile' class files and see if a Java implementation is really as
secure as it should be. <p>
<hr><address>Copyright (c) Jonathan Meyer, July 1996</address>
<hr>
<a href="http://jasmin.sourceforge.net">Jasmin Home</a> |
<a href="http://www.cybergrain.com/">Jon Meyer's Home</a>

View file

@ -0,0 +1,689 @@
<html>
<head>
<title>Jasmin User Guide</title>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
<table>
<tr><td width=550>
<center>
<p><img src=jasmin_icon.jpg></p>
<p>
<div class="h1">JASMIN USER GUIDE</div>
Jonathan Meyer, July 1996
</p>
</center>
<h1>About This Document</h1>
This guide describes the rules and syntax used in Jasmin, and
how to run Jasmin. Note that this document doesn't
explain the Java Virtual Machine itself, or give syntax notes for
every instruction known to Jasmin. See the Java Virtual Machine specification
for more information on the JVM.<p>
<h1>What is Jasmin?</h1>
<p>
Jasmin is an assembler for the Java Virtual Machine. It takes
ASCII descriptions of Java classes, written in a simple
assembler-like syntax using the Java Virtual
Machine instruction set. It converts them into binary Java class files,
suitable for loading by a Java runtime system.<p>
</p>
<p>
Jasmin was originally created as a companion to the book "Java Virtual Machine",
written by Jon Meyer and Troy Downing and published by O'Reilly Associates. The
book is now out of print. Jasmin survives as a SourceForge Open Source project.
</p>
<h1>Jasmin Design</h1>
<p>
Jasmin is designed as a simple assembler. It has a clean easy-to-learn
syntax with few bells and whistles. Where possible, Jasmin adopts a
one-to-one mapping between its syntax and the conventions followed by Java class files.
For example, package names in Jasmin are delimited with the '/' character
(e.g. "java/lang/String") used by the class file format, instead
of the '.' character (java.lang.String) used in the Java language.</p>
<p>
The Jasmin assembler does little compile-time processing or
checking of the input code. For example, it doesn't check that
classes you reference actually exist, or that your type descriptors are
well formed. Jasmin also lacks many of the feautures
found in full macro assemblers. For example, it doesn't
inline mathematical expressions, perform variable
substitutions, or support macros.</p>
<p>
On the other hand, using Jasmin you can quickly try out nearly
all of the features of the Java Virtual Machine, including
methods, fields, subroutines, exception handlers, and so on.
The Jasmin syntax is also readable and compact.</p>
<h1>Running Jasmin</h1>
<p>
The <code>jasmin.jar</code> file is an executable JAR file that runs Jasmin.
For example:</p>
<pre><strong> java -jar jasmin.jar myfile.j</strong></pre>
<p>assembles the file "myfile.j". Jasmin looks at the
<code>.class</code> directive contained in the file to
decide where to place the output class file. So if myfile.j starts
with:</p>
<pre>
.class mypackage/MyClass
</pre>
<p>then Jasmin will place the output class file "MyClass.class" in the
subdirectory "mypackage" of the current directory. It will create the
mypackage directory if it doesn't exist.</p>
<p>You can use the "-d" option to tell jasmin to place the output
in an alternative directory. For example,</p>
<pre><strong> java -jar jasmin.jar -d /tmp myfile.j </strong></pre>
<p>will place the output in /tmp/mypackage/MyClass.class.</p>
<p>Finally, you can use the "-g" option to tell Jasmin to include
line number information (used by debuggers) in the resulting
.class file. Jasmin will number the lines in the Jasmin source
file that JVM instructions appear on. Then, if an error occurs,
you can see what instruction in the Jasmin source caused the error.
Note that specifying "-g" causes any .line directives within the
Jasmin file to be ignored.
</p>
<h1>Statements</h1>
<p>Jasmin source files consists of a sequence of newline-separated statements.
There are three types of statement: </p>
<ul>
<li>directives
<li>instructions
<li>labels
</ul>
<p>
Directives and instructions can take <i>parameters</i>. These parameters
are placed on the same line as the directive or instruction,
separated by spaces.</p>
<h3>Directives</h3>
<p>
Directive statements are used to give Jasmin meta-level information.
Directive statements consist of a directive name, and then zero or more
parameters separated by spaces, then a newline.</p>
<p>
All directive names start with a "." character. The directives in Jasmin are:</p>
<pre>
.catch .class .end .field .implements .interface .limit .line
.method .source .super .throws .var
</pre>
<p>
Some example directive statements are:</p>
<pre>
.limit stack 10
.method public myMethod()V
.class Foo
</pre>
<p>
The parameters used by each directive are described in more detail
later in the document.</p>
<h3>Instructions</h3>
<p>
An instruction statement consists of an instruction name, zero or
more parameters separated by spaces, and a newline.</p>
<p>
Jasmin uses the standard mnemonics for JVM opcodes as instruction names.
For example, aload_1, bipush and iinc are all Jasmin instruction names.</p>
<p>
Here are some examples of instruction statements:</p>
<pre>
ldc "Hello World"
iinc 1 -1
bipush 10
</pre>
<p>
</p>See <a href="instructions.html">Jasmin Instructions</a> for more details on
the syntax of instructions in Jasmin.</p>
<h3>Labels</h3>
<p>
</p>A Jasmin label statement consists of a name followed by a ':', and a newline.
For example:</p>
<pre>
Foo:
Label:
</pre>
<p>Label names cannot start with a numeric digit, and cannot contain
any of the special characters:</p>
<pre>
= : . " -
</pre>
<p>
You cannot use directive names or instruction names as labels. Other
than that, there are few restrictions on label names.
For example, you could use the label:</p>
<pre>
#_1:
</pre>
<p>
Labels can only be used within method definitions. The names are
local to that method.</p>
<h1>The Jasmin Tokenizer</h1>
<p>
Jasmin tokenizes its input stream, splitting the stream into tokens
by looking for whitespace characters (spaces, tabs and newlines).
The tokenizer looks for:</p>
<ul>
<li>directive names
<li>instruction names
<li>labels
<li>comments
<li>type descriptor names
<li>class names
<li>numbers and quoted strings
<li>etc.
</ul>
<p>
The rules used by the tokenizer are described below:</p>
<h3>Comments</h3>
<p>
A comment is a token that starts with a ';' character, and
terminates with the newline character at the end of the line. </p>
<p>
Note that the semicolon must be preceded by a whitespace character (a space, tab, newline), i.e.
embedded semicolons are ignored. For example,</p>
<pre>
abc;def
</pre>
<p>
is treated as a single token "abc;def", and</p>
<pre>
Ljava/lang/String;
</pre>
<p>
is the token "Ljava/lang/String;", whereas</p>
<pre>
foo ; baz ding
</pre>
<p>
is the token "foo" followed by a comment "baz ding".</p>
<h3>Numbers and Strings</h3>
<p>
In Jasmin, only simple decimal and integer numeric formats are
recognized. Floats in scientific or exponent format are not yet
supported. Character codes and octal aren't currently supported either. This
means you can have:</p>
<pre>
1, 123, .25, 0.03, 0xA
</pre>
<p>
but not</p>
<pre>
1e-10, 'a', '\u123'
</pre>
<p>
Quoted strings are also very basic. The full range of
backslash escape sequences are not supported yet, although "\n" and "\t"
are.</p>
<h3>Class Names</h3>
<p></p>Class names in Jasmin should be written using the Java class file format
conventions, so java.lang.String becomes java/lang/String.</p>
<h3>Type Descriptors</h3>
<p>
Type information is also written as they appear in class files (e.g.
the descriptor I speficies an integer, [Ljava/lang/Thread; is an
array of Threads, etc.).</p>
<h3>Methods</h3>
<p>
Method names are specified using a single token, e.g.</p>
<pre>
java/io/PrintStream/println(Ljava/lang/String;)V
</pre>
<p>
is the method called "println" in the class java.io.PrintStream, which
has the type descriptor "(Ljava/lang/String;)V" (i.e. it takes a String
and returns no result). In general, a method specification
is formed of three parts: the characters before the last '/' form the class
name. The characters between the last '/' and '(' are the method name. The
rest of the string is the type descriptor for the method.</p>
<pre>
foo/baz/Myclass/myMethod(Ljava/lang/String;)V
--------------- ---------------------
| -------- |
| | |
class method descriptor
</pre>
<p>
As another example, you would call the Java method: </p>
<pre>
class mypackage.MyClass {
int foo(Object a, int b[]) { ... }
}
</pre>
<p>
using:</p>
<pre>
invokevirtual mypackage/MyClass/foo(Ljava/lang/Object;[I)I
</pre>
<h3>Fields</h3>
<p>
Field names are specified in Jasmin using two tokens, one giving the name
and class of the field, the other giving its descriptor. For example:</p>
<pre>
getstatic mypackage/MyClass/my_font Ljava/lang/Font;
</pre>
<p>
gets the value of the field called "my_font" in the class mypackage.MyClass.
The type of the field is "Ljava/lang/Font;" (i.e. a Font object).</p>
<h1>FILES</h1>
<p>
Jasmin files start by giving information on the class
being defined in the file - such as the name of the
class, the name of the source file that the class originated from,
the name of the superclass, etc.</p>
<p>
Typically, a Jasmin file starts with the three directives:</p>
<pre>
.source &lt;source-file&gt;
.class &lt;access-spec&gt; &lt;class-name&gt;
.super &lt;class-name&gt;
</pre>
<p>
For example, the file defining MyClass might start with the directives:</p>
<pre>
.source MyClass.j
.class public MyClass
.super java/lang/Object
</pre>
<h3>.source directive</h3>
<p>
The .source directive is optional. It specifies the
value of the "SourceFile" attribute for the class
file. (This is used by Java to print out debugging info
if something goes wrong in one of the methods in the class).
If you generated the Jasmin file automatically (e.g. as the result of
compiling a file written in another syntax) you should use the .source
directive to tell Java the name of the originating file. Note that
the source file name should not include any pathname. Use "foo.src"
but not "/home/user/foo.src".</p>
<p>
If no .source directive is given, the name of the Jasmin
file you are compiling is used instead as the SourceFile attribute
instead.</p>
<h3>.class and .super directives</h3>
<p>
The .class and .super directive tell the JVM the name of this
class and its superclass. These directives take parameters as
follows:
</p>
<dl>
<dt>&lt;class-name&gt;</dt>
<dd>is the full name of the class, including
any package names. For example foo/baz/MyClass.<p>
</dd>
<dt>&lt;access-spec&gt;</dt>
<dd>defines access permissions and other attributes for
the class. This is a list of zero or more of the following
keywords:<p>
<dl><dd>
public, final, super, interface, abstract
</dl>
</dl>
<h3>.interface directive</h3>
<p>
Note that, instead of using the directive .class,
you can alternatively use the directive .interface. This has
the same syntax as the .class directive, but indicates that the Jasmin file
is defining a Java interface. e.g.</p>
<pre>
.interface public foo
</pre>
<h3>.implements directive</h3>
<p>
After .source, .class and .super, you can list the
interfaces that are implemented by the class you are defining, using
the .implements directive. The syntax of .implements is:</p>
<pre>
.implements &lt;class-name&gt;
</pre>
<p>
where &lt;class-name&gt; has the same format as was used by .class and .super.
For example:</p>
<pre>
.class foo
.super java/lang/Object
.implements Edible
.implements java/lang/Throwable
</pre>
<h1>Field Definitions</h1>
<p>
After the header information, the next section of the Jasmin file
is a list of field definitions.</p>
<p>
A field is defined using the .field directive:</p>
<pre>
.field &lt;access-spec&gt; &lt;field-name&gt; &lt;descriptor&gt; [ = &lt;value&gt; ]
</pre>
<p>
where:</p>
<dl>
<dt>&lt;access-spec&gt;
<dd>is one of the keywords:
<dl><dd>
public, private, protected, static, final,
volatile, transient
</dl>
</dl><p>
<dt>&lt;field-name&gt;
<dd>is the name of the field.<p>
<dt>&lt;descriptor&gt;
<dd>is its type descriptor.<p>
<dt>&lt;value&gt;
<dd>is an integer, a quoted string or a decimal number, giving the
initial value of the field (for final fields).<p>
</dl>
<p>
For example, the Java field definition:</p>
<pre>
public int foo;
</pre>
<p>
becomes</p>
<pre>
.field public foo I
</pre>
<p>
whereas the constant:</p>
<pre>
public static final float PI = 3.14;
</pre>
<p>
becomes</p>
<pre>
.field public static final PI F = 3.14
</pre>
<h1>Method Definitions</h1>
<p>
After listing the fields of the class, the rest of the Jasmin file lists
methods defined by the class.</p>
<p>
A method is defined using the basic form:</p>
<pre>
.method &lt;access-spec&gt; &lt;method-spec&gt;
&lt;statements&gt;
.end method
</pre>
<p>
where:</p>
<dl>
<dt>&lt;access-spec&gt;
<dd>is one of the keywords: public, private, protected, static, final,
synchronized, native, abstract<p>
<dt>&lt;method-spec&gt;
<dd>is the name and type descriptor of the method.<p>
<dt>&lt;statements&gt;
<dd>is the code defining the body of the method.<p>
</dl>
<p>
Method definitions cannot be nested. Also, Jasmin does not
insert an implicit 'return' instruction at the end of a method. It is
up to you to ensure that your methods return cleanly. So
the most basic Jasmin method is something like:</p>
<pre>
.method foo()V
return ; must give a return statement
.end method
</pre>
<h3>Method Directives</h3>
<p>
The following directives can be used only within method definitions:</p>
<dl>
<dt><pre>.limit stack &lt;integer&gt;</pre><p>
<dd>Sets the maximum size of the operand stack
required by the method.
<dt><pre>.limit locals &lt;integer&gt;</pre><p>
<dd>Sets the number of local variables
required by the method.
<dt><pre>.line &lt;integer&gt;</pre><p>
<dd>This is used to tag the subsequent
instruction(s) with a line number. Debuggers use this information,
together with the name of the source file (see .source above)
to show at what line in a method things went wrong. If you are
generating Jasmin files by compiling a source file,
this directive lets you indicate what line
numbers in the source file produced corrosponding Jasmin
instructions. For example:
<pre>
.method foo()V
.line 5
bipush 10 // these instructions generated from line 5
istore_2 // of the source file.
.line 6
...
</pre>
<dt><pre>.var &lt;var-number&gt; is &lt;name&gt; &lt;descriptor&gt; from &lt;label1&gt; to &lt;label2&gt;</pre><p>
<dd>The .var directive is used to define the name, type descriptor and scope of
a local variable number. This information is used by debuggers
so that they can be more helpful when printing out the values of local
variables (rather than printing just a local variable number, the
debugger can actually print out the name of the variable). For example:
<pre>
.method foo()V
.limit locals 1
; declare variable 0 as an "int Count;"
; whose scope is the code between Label1 and Label2
;
.var 0 is Count I from Label1 to Label2
Label1:
bipush 10
istore_0
Label2:
return
.end method
</pre>
<dt><pre>.throws &lt;classname&gt;</pre><p>
<dd>Indicates that this method can throw
exceptions of the type indicated by &lt;classname&gt;.
e.g.
<pre>
.throws java/io/IOException
</pre>
This information isn't required by Java runtime systems,
but it is used by the Java compiler to check that methods
either catch exceptions they can cause, or declare
that they throw them.
<dt><pre>.catch &lt;classname&gt; from &lt;label1&gt; to &lt;label2&gt; using &lt;label3&gt;</pre><p>
<dd>Appends an entry to the end of the exceptions table for the
method. The entry indicates that when an exception which is
an instance of &lt;classname&gt; or one of its subclasses is thrown
while executing the code between &lt;label1&gt; and &lt;label2&gt;, then
the runtime system should jump to &lt;label3&gt;. e.g.<p>
<pre>
.catch java/io/IOException from L1 to L2 using IO_Handler
</pre>
If classname is the keyword "all", then exceptions of any
class are caught by the handler.<p>
</dl>
<h3>Abstract Methods</h3>
<p>
To declare an abstract method, write a method with no body. e.g.</p>
<pre>
.method abstract myAbstract()V
.end method
</pre>
<p>
note that abstract methods can have .throws directives, e.g.</p>
<pre>
.method abstract anotherAbstract()V
.throws java/io/IOException
.end method
</pre>
<h1>Instructions</h1>
<p>
JVM instructions are placed between the <code>.method</code> and
<code>.end method</code> directives. VM instructions can take zero or more
parameters, depending on the type of instruction used. Some example
instructions are shown below:
</p>
<pre>
iinc 1 -3 ; decrement local variable 1 by 3
bipush 10 ; push the integer 10 onto the stack
pop ; remove the top item from the stack.
</pre>
<p>
See <a href="instructions.html">Jasmin Instructions</a> for more details on the syntax
of instructions in Jasmin.
</p>
<hr><address>Copyright (c) Jonathan Meyer, July 1996</address>
<hr>
<a href="http://jasmin.sourceforge.net">Jasmin Home</a> |
<a href="http://www.cybergrain.com">Jon Meyer's Home</a>
</td></tr></table>
</body>
</html>

View file

@ -0,0 +1,65 @@
<html>
<head>
<title>Jasmin Home Page</title>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
<table>
<tr><td width=550>
<center>
<p><img src=jasmin_icon.jpg></p>
<p>
<div class="h1">JASMIN HOME PAGE</div>
Jonathan Meyer, Oct 2004
</p>
</center>
<h1>Introduction</h1>
<p>
Jasmin is an assembler for the Java Virtual Machine. It takes
ASCII descriptions of Java classes, written in a simple
assembler-like syntax using the Java Virtual
Machine instruction set. It converts them into binary Java class files,
suitable for loading by a Java runtime system.<p>
</p>
<p>
Jasmin was originally created as a companion to the book "Java Virtual Machine",
written by Jon Meyer and Troy Downing and published by O'Reilly Associates.
Since then, it has become the de-facto standard assembly format for Java. It is used in dozens of compiler classes throughout the world, and has
been ported and cloned multiple times. For better or worse, Jasmin remains the oldest and the original Java assembler.
</p>
<p>
The O'Reilly JVM book is now out of print. Jasmin continues to survive as a SourceForge Open Source project.
</p>
<h1>Documentation</h1>
<dl>
<dt>
<a href = "http://jasmin.sourceforge.net">Jasmin Home Page</a>
<dd>this file (on SourceForge.net).<p>
<dt>
<a href = "guide.html">Jasmin User Guide</a>
<dd>a brief user guide for using Jasmin.<p>
<dt><a href = "instructions.html">Jasmin Instructions</a>
<dd>the syntax of JVM instructions in Jasmin.<p>
<dt>
<a href = "about.html">About Jasmin</a>
<dd>describes the background to Jasmin, who might find it interesting, etc.
Includes an example piece of Jasmin assembler to look at.<p>
</dl>
<hr><address>Copyright (c) Jonathan Meyer, 2004</address>
<hr>
<a href="http://jasmin.sourceforge.net">Jasmin Home</a> |
<a href="http://www.cybergrain.com">Jon Meyer's Home</a>
</td></tr></table>
</body>
</html>

View file

@ -0,0 +1,505 @@
<html>
<head>
<title>Jasmin Instructions</title>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
<table ID="Table1">
<tr><td width=550>
<center>
<p><img src=jasmin_icon.jpg></p>
<p>
<div class="h1">JASMIN INSTRUCTIONS</div>
Jonathan Meyer, July 1996
</p>
</center>
<h1>Introduction</h1>
This document shows the syntax and the types of parameters required by
each Java VM instruction in Jasmin. It also shows brief illustrative
examples.<p>
See <a href="guide.html">The Jasmin User Guide</a> for a description
of other aspects of the Jasmin syntax.<p>
<h1>Local variable instructions</h1>
The following instructions use local variables:<p>
<pre>
ret &lt;var-num&gt;
aload &lt;var-num&gt;
astore &lt;var-num&gt;
dload &lt;var-num&gt;
dstore &lt;var-num&gt;
fload &lt;var-num&gt;
fstore &lt;var-num&gt;
iload &lt;var-num&gt;
istore &lt;var-num&gt;
lload &lt;var-num&gt;
lstore &lt;var-num&gt;
</pre>
for example:<p>
<pre>
aload 1 ; push local variable 1 onto the stack
ret 2 ; return to the address held in local variable 2
</pre>
<h1>The bipush, sipush and iinc instructions</h1>
The bipush and sipush instructions take an integer as a
parameter:<p>
<pre>
bipush &lt;int&gt;
sipush &lt;int&gt;
</pre>
for example:<p>
<pre>
bipush 100 ; push 100 onto the stack
</pre>
The iinc instruction takes two integer parameters:<p>
<pre>
iinc &lt;var-num&gt; &lt;amount&gt;
</pre>
for example:<p>
<pre>
iinc 3 -10 ; subtract 10 from local variable 3
</pre>
<h1>Branch instructions</h1>
The following instructions take a label as a parameter:
<pre>
goto &lt;label&gt;
goto_w &lt;label&gt;
if_acmpeq &lt;label&gt;
if_acmpne &lt;label&gt;
if_icmpeq &lt;label&gt;
if_icmpge &lt;label&gt;
if_icmpgt &lt;label&gt;
if_icmple &lt;label&gt;
if_icmplt &lt;label&gt;
if_icmpne &lt;label&gt;
ifeq &lt;label&gt;
ifge &lt;label&gt;
ifgt &lt;label&gt;
ifle &lt;label&gt;
iflt &lt;label&gt;
ifne &lt;label&gt;
ifnonnull &lt;label&gt;
ifnull &lt;label&gt;
jsr &lt;label&gt;
jsr_w &lt;label&gt;
</pre>
For example:<p>
<pre>
Label1:
goto Label1 ; jump to the code at Label1
; (an infinite loop!)
</pre>
<h1>Class and object operations</h1>
The following instructions take a class name
as a parameter:
<pre>
anewarray &lt;class&gt;
checkcast &lt;class&gt;
instanceof &lt;class&gt;
new &lt;class&gt;
</pre>
For example:<p>
<pre>
new java/lang/String ; create a new String object
</pre>
<h1>Method invokation</h1>
The following instructions are used to invoke methods:<p>
<pre>
invokenonvirtual &lt;method-spec&gt;
invokestatic &lt;method-spec&gt;
invokevirtual &lt;method-spec&gt;
</pre>
for example:<p>
<pre>
; invokes java.io.PrintStream.println(String);
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
</pre>
A method specification is formed of three parts: the characters before the
last '/' form the class name. The characters between the last '/' and '(' are
the method name. The rest of the string is the descriptor.<p>
<pre>
foo/baz/Myclass/myMethod(Ljava/lang/String;)V
--------------- ---------------------
| -------- |
| | |
class method descriptor
</pre>
A special case is invokeinterface, which takes a &lt;method-spec&gt; and
an integer indicating how many arguments the method takes:<p>
<pre>
invokeinterface &lt;method-spec&gt; &lt;num-args&gt;
</pre>
for example:<p>
<pre>
invokeinterface foo/Baz/myMethod(I)V 1
</pre>
<h1>Field manipulation instructions</h1>
The four instructions getfield, getstatic, putfield and
putstatic have the form:<p>
<pre>
getfield &lt;field-spec&gt; &lt;descriptor&gt;
getstatic &lt;field-spec&gt; &lt;descriptor&gt;
putfield &lt;field-spec&gt; &lt;descriptor&gt;
putstatic &lt;field-spec&gt; &lt;descriptor&gt;
</pre>
for example:
<pre>
; get java.lang.System.out, which is a PrintStream
getstatic java/lang/System/out Ljava/io/PrintStream;
</pre>
&lt;field-spec&gt; is composed of two parts, a classname and a fieldname. The
classname is all of the characters in the &lt;field-spec&gt; up to the last
'/' character, and the fieldname is the rest of the characters after the last
'/'. For example: <p>
<pre>
foo/baz/AnotherClass/anotherFunField
-- class name ------ --field name --
</pre>
&lt;descriptor&gt; is the Java type descriptor of the field.
For example:<p>
<pre>
Ljava/io/PrintStream;
</pre>
<h1>The newarray instruction</h1>
The newarray instruction is followed by the type of the array,<p>
<pre>
newarray &lt;array-type&gt;
</pre>
for example:<p>
<pre>
newarray int
newarray short
newarray float
etc.
</pre>
<h1>The multianewarray instruction</h1>
The multianewarray instruction takes two parameters,
the type descriptor for the array and the number of
dimensions to allocate:<p>
<pre>
multianewarray &lt;array-descriptor&gt; &lt;num-dimensions&gt;
</pre>
for example:<p>
<pre>
multianewarray [[[I 2
</pre>
<h1>The ldc and ldc_w instructions</h1>
The ldc and ldc_w instructions are followed by a constant:<p>
<pre>
ldc &lt;constant&gt;
ldc_w &lt;constant&gt;
</pre>
&lt;constant&gt; is either an integer, a floating point number, or a
quoted string. For example:<p>
<pre>
ldc 1.2 ; push a float
ldc 10 ; push an int
ldc "Hello World" ; push a String
ldc_w 3.141592654 ; push PI as a double
</pre>
<h1>The lookupswitch instruction</h1>
The lookupswitch instruction has the syntax:<p>
<pre>
&lt;lookupswitch&gt; ::=
lookupswitch
&lt;int1&gt; : &lt;label1&gt;
&lt;int2&gt; : &lt;label2&gt;
...
default : &lt;default-label&gt;
</pre>
For example:<p>
<pre>
; If the int on the stack is 3, jump to Label1.
; If it is 5, jump to Label2.
; Otherwise jump to DefaultLabel.
lookupswitch
3 : Label1
5 : Label2
default : DefaultLabel
Label1:
... got 3
Label2:
... got 5
DefaultLabel:
... got something else
</pre>
<h1>The tableswitch instruction</h1>
The tableswitch instruction has the syntax:<p>
<pre>
&lt;tableswitch&gt; ::=
tableswitch &lt;low&gt;
&lt;label1&gt;
&lt;label2&gt;
...
default : &lt;default-label&gt;
</pre>
For example:<p>
<pre>
; If the int on the stack is 0, jump to Label1.
; If it is 1, jump to Label2.
; Otherwise jump to DefaultLabel.
tableswitch 0
Label1
Label2
default : DefaultLabel
Label1:
... got 0
Label2:
... got 1
DefaultLabel:
... got something else
</pre>
<h1>No parameter</h1>
The following instructions (the majority) take no parameters:<p>
<dl><dd>
aaload
aastore
aconst_null
aload_0
aload_1
aload_2
aload_3
areturn
arraylength
astore_0
astore_1
astore_2
astore_3
athrow
baload
bastore
breakpoint
caload
castore
d2f
d2i
d2l
dadd
daload
dastore
dcmpg
dcmpl
dconst_0
dconst_1
ddiv
dload_0
dload_1
dload_2
dload_3
dmul
dneg
drem
dreturn
dstore_0
dstore_1
dstore_2
dstore_3
dsub
dup
dup2
dup2_x1
dup2_x2
dup_x1
dup_x2
f2d
f2i
f2l
fadd
faload
fastore
fcmpg
fcmpl
fconst_0
fconst_1
fconst_2
fdiv
fload_0
fload_1
fload_2
fload_3
fmul
fneg
frem
freturn
fstore_0
fstore_1
fstore_2
fstore_3
fsub
i2d
i2f
i2l
iadd
iaload
iand
iastore
iconst_0
iconst_1
iconst_2
iconst_3
iconst_4
iconst_5
iconst_m1
idiv
iload_0
iload_1
iload_2
iload_3
imul
ineg
int2byte
int2char
int2short
ior
irem
ireturn
ishl
ishr
istore_0
istore_1
istore_2
istore_3
isub
iushr
ixor
l2d
l2f
l2i
ladd
laload
land
lastore
lcmp
lconst_0
lconst_1
ldiv
lload_0
lload_1
lload_2
lload_3
lmul
lneg
lor
lrem
lreturn
lshl
lshr
lstore_0
lstore_1
lstore_2
lstore_3
lsub
lushr
lxor
monitorenter
monitorexit
nop
pop
pop2
return
saload
sastore
swap
</dl>
for example:
<pre>
pop ; remove the top item from the stack
iconst_1 ; push 1 onto the stack
swap ; swap the top two items on the stack
</pre>
<hr><address>Copyright (c) Jonathan Meyer, July 1996</address>
<hr>
<a href="http://mrl.nyu.edu/meyer/jvm/jasmin.html">Jasmin Home</a> |
<a href="http://mrl.nyu.edu/meyer/">Jon Meyer's Home</a>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

View file

@ -0,0 +1,16 @@
td { font-family: Verdana,Arial,Helvetica,sans-serif; color: #000000; font-size: 12px; line-height: 16px; }
td h1 { font-family: Tahoma; padding: 1px; padding-left: 4px; color: white; background-color: #303030; font-size: 20px; line-height: 24px; font-weight: bold; }
td h2{ font-family: Tahoma; color: #000000; font-size: 14px; line-height: 16px; font-weight: bold; }
td h3 { font-family: Tahoma; color: #000000; font-size: 12px; line-height: 16px; font-weight: bold; }
.h1 { font-family: Times; color: #000000; font-size: 18px; line-height: 20px; font-weight: bold; }
/* main text hyperlinks */
a { color: #b11; TEXT-DECORATION: underline; }
a:visited {color: #b11}
a:hover {color: #f88}
pre.code{ font-family: courier new; color: #202060; font-size: 12px; line-height: 14px;}
font.code{ font-family: courier new; color: #202060; font-size: 12px; line-height: 14px;}

View file

@ -0,0 +1,88 @@
Jasmin Syntax Jonathan Meyer, April 1996
This file contains a simplified BNF version of the Jasmin syntax.
jasmin_file ::=
'.class' [ <access> ] <name> <break>
'.super' <name> <break>
[ <fields> ]
[ <methods> ]
<fields> ::= <field> [ <field> ... ]
<field> ::=
'.field' <access> <name> <signature> [ = <default> ] <break>
<default> ::= <int> | <quoted_string> | <float>
<methods> ::= <method> [ <method> ... ]
<method> ::=
'.method' <access> <name> <break>
[ <statements> ]
'.end' 'method' <break>
<statements> ::= <statement> [ <statement> ... ]
<statement> ::=
<directive> <break>
|
<instruction> <break>
|
<label> ':' <break>
<directive> ::=
'.limit' 'stack' <val>
|
'.limit' 'locals' <val>
|
'.throws' <classname>
|
'.catch' <classname> 'from' <label1> 'to' <label2> 'using' <label3>
<instruction> ::= <simple_instruction> | <complex_instruction>
<simple_instruction> ::=
<insn>
|
<insn> <int> <int>
|
<insn> <int>
|
<insn> <num>
|
<insn> <word>
|
<insn> <word> <int>
|
<insn> <word> <word>
|
<insn> <quoted_string>
<complex_instruction> ::=
<lookupswitch>
|
<tableswitch>
<lookupswitch> ::=
lookupswitch <nl>
<int> : <label> <nl>
<int> : <label> <nl>
...
default : <label>
<tableswitch> ::=
tableswitch <low> <nl>
<label> <nl>
<label> <nl>
...
default : <label>
<access> ::= <access_item> [ <access_item> ... ]
<access_item> ::=
'public' | 'private' | 'protected' | 'static' | 'final' |
'synchronized' | 'volatile' | 'transient' | 'native' |
'interface' | 'abstract'

View file

@ -0,0 +1,52 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/ANewArray.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Shows how to use anewarray instruction
; -------------------------------------------------------------------------
;
; This class demonstrates how to allocate a multidimensional
; array using anewarray.
;
.class public examples/ANewArray
.super java/lang/Object
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 4
.limit locals 2
;
; Allocates an array like:
; String x[][] = new String[2][5]
;
; Allocate spine for array and store it in local var 1
; (i.e. String[2][])
iconst_2
anewarray [Ljava/lang/String;
astore_1
; allocate first array of String[5] and store it in index 0
aload_1
iconst_0
bipush 5
anewarray java/lang/String
aastore
; allocate second array of String[5] and store it in index 1
aload_1
iconst_1
bipush 5
anewarray java/lang/String
aastore
; done ...
return
.end method

View file

@ -0,0 +1,31 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/AnInterface.j
; Author: Jonathan Meyer, 1 Oct 1996
; Purpose: A Java interface written in Jasmin
; -------------------------------------------------------------------------
;
; This file shows how to use Jasmin to define an interface. It
; is like the Java code:
;
; interface public examples.AnInterface {
; void foo();
; }
;
; See examples.Implementor for an example of a class that implements
; this interface.
;
.interface public examples/AnInterface
.super java/lang/Object
; (Interfaces should either inherit from Object, or from
; another interface.)
;
; declare abstract method foo() - note that the method body is empty.
;
.method abstract foo()V
.end method

View file

@ -0,0 +1,53 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/Arrays.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Example using JVM's anewarray and aaload/aastore
; -------------------------------------------------------------------------
;
; This illustrates how to use the various JVM array instructions - though
; it doesn't actually do anything very interesting with the arrays.
;
.class public examples/Arrays
.super java/lang/Object
; standard initializer
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit locals 2
.limit stack 4
; creates a new array of strings,
; like:
; String[] myarray = new String[2];
iconst_2
anewarray java/lang/String
astore_1 ; stores this in local variable 1
; this is like the code:
; myarray[0] = args[0];
aload_1 ; push my array on the stack
iconst_0
aload_0 ; push the array argument to main() on the stack
iconst_0
aaload ; get its zero'th entry
aastore ; and store it in my zero'th entry
; now print out myarray[0]
getstatic java/lang/System/out Ljava/io/PrintStream;
aload_1
iconst_0
aaload
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
; done
return
.end method

View file

@ -0,0 +1,79 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/Catch.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Catching and throwing exceptions
; -------------------------------------------------------------------------
;
; This hows how to throw and catch Exceptions in Jasmin
;
.class public examples/Catch
.super java/lang/Object
; standard initializer
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object.<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit locals 3
.limit stack 5
; set up a handler to catch subclasses of java.lang.Exception
.catch java/lang/Exception from Label1 to Label2 using Handler
; store System.out in local variable 1
getstatic java/lang/System/out Ljava/io/PrintStream;
astore_1
; print out a message
aload_1
ldc " -- Before exception"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
; construct an instance of Exception, initialize it with a string,
; throw it. This is like the Java statement :
;
; throw new Exception("My exception");
;
Label1:
new java/lang/Exception
dup
ldc "<my exception>"
invokenonvirtual java/lang/Exception/<init>(Ljava/lang/String;)V
athrow
Label2:
aload_1
ldc " -- After exception"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
return
; This is the handler for the exception
Handler:
; store the exception in local variable 2
astore_2
; print out a message
aload_1
ldc " -- Caught exception: "
invokevirtual java/io/PrintStream/print(Ljava/lang/String;)V
; call getMessage() to retrieve the message from the Exception...
aload_1
aload_2
invokevirtual java/lang/Throwable/getMessage()Ljava/lang/String;
; ... now print it
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
; return to the code
goto Label2
.end method

View file

@ -0,0 +1,35 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/Checkcast.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Catching and throwing exceptions
; -------------------------------------------------------------------------
;
; Simple test for checkcast instruction
;
.class examples/Checkcast
.super java/lang/Object
;
; standard initializer
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 2
; push System.out onto the stack
getstatic java/lang/System/out Ljava/io/PrintStream;
; check that it is a PrintStream
checkcast java/io/PrintStream
; done
return
.end method

View file

@ -0,0 +1,56 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/Count.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Counts from 0 to 9, printing out the value
; -------------------------------------------------------------------------
.class public examples/Count
.super java/lang/Object
;
; standard initializer
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
; set limits used by this method
.limit locals 4
.limit stack 3
; setup local variables:
; 1 - the PrintStream object held in java.lang.System.out
getstatic java/lang/System/out Ljava/io/PrintStream;
astore_1
; 2 - the integer 10 - the counter used in the loop
bipush 10
istore_2
; now loop 10 times printing out a number
Loop:
; compute 10 - <local variable 2> ...
bipush 10
iload_2
isub
invokestatic java/lang/String/valueOf(I)Ljava/lang/String;
astore_3
; ... and print it
aload_1 ; push the PrintStream object
aload_3 ; push the string we just created - then ...
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
; decrement the counter and loop
iinc 2 -1
iload_2
ifne Loop
; done
return
.end method

View file

@ -0,0 +1,5 @@
This shows how to run HelloApplet:<p>
<applet code="HelloWeb.class" width=350 height=75>
</applet>

View file

@ -0,0 +1,91 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/HelloWeb.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Demonstration of a Jasmin-created applet
; -------------------------------------------------------------------------
; HelloWeb.j
; This demonstrates how you can use Jasmin to create an applet.
; The code below is like the Java code:
;
; import java.applet.*;
; import java.awt.*;
;
; public class HelloWeb extends Applet {
; private Font font;
;
; public void init() {
; font = new Font("Helvetica", Font.BOLD, 48);
; }
;
; public void paint(Graphics g) {
; g.setFont(font);
; g.drawString("Hello World!", 25, 50);
; }
; }
.class public HelloWeb
.super java/applet/Applet
.field private font Ljava/awt/Font;
; my init() method - allocate a font and assign it to this.font.
.method public init()V
.limit stack 5
; Create a new Font and call its constructor with
; "Helvetica", 1 (i.e. Font.BOLD), and 48.
new java/awt/Font
dup
ldc "Helvetica"
iconst_1
bipush 48
invokenonvirtual java/awt/Font/<init>(Ljava/lang/String;II)V
; now store the Font on the stack in this.font
aload_0
swap
putfield HelloWeb/font Ljava/awt/Font;
; done
return
.end method
; my paint() method - draws the string "Hello World!" using this.font.
.method public paint(Ljava/awt/Graphics;)V
.limit stack 4
.limit locals 2
; local variable 0 holds <this>
; local variable 1 holds the java.awt.Graphics instance ('g').
; g.setFont(this.font);
aload_1
aload_0
getfield HelloWeb/font Ljava/awt/Font;
invokevirtual java/awt/Graphics/setFont(Ljava/awt/Font;)V
; g.drawString("Hello Web!", 25, 50);
aload_1
ldc "Hello Web!"
bipush 25
bipush 50
invokevirtual java/awt/Graphics/drawString(Ljava/lang/String;II)V
; done
return
.end method
; standard constructor
.method public <init>()V
aload_0
invokenonvirtual java/applet/Applet/<init>()V
return
.end method

Binary file not shown.

View file

@ -0,0 +1,35 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/HelloWorld.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Prints out "Hello World!"
; -------------------------------------------------------------------------
.class public NoJad.j
.super java/lang/Object
;
; standard initializer
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 2
.limit locals 2
bipush 2
astore 0
bipush 3
astore 1
aload 0
aload 1
astore 0
astore 1
return
.end method

View file

@ -0,0 +1,53 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/HelloWorld.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Shows how to define a class that implements an interface
; -------------------------------------------------------------------------
;
; This class implements the examples.AnInterface interface - see
; AnInterface.j
;
.class public examples/Implementor
.super java/lang/Object
.implements examples/AnInterface
;
; standard initializer
;
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
;
; implement the foo()V method - this is an interface method
;
.method public foo()V
.limit stack 2
; print a simple message
getstatic java/lang/System/out Ljava/io/PrintStream;
ldc "Hello Interface"
invokevirtual java/io/PrintStream/println(Ljava/lang/String;)V
; done
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 2
; create a new one of me
new examples/Implementor
dup
invokenonvirtual examples/Implementor/<init>()V
; now call my interface method foo()
invokeinterface examples/AnInterface/foo()V 1
return
.end method

View file

@ -0,0 +1,45 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/InvokeInterface.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Example of using invokeinterface
; -------------------------------------------------------------------------
;
; Demonstrates invoking an interface method
;
.class public examples/InvokeInterface
.super java/lang/Object
; standard initializer
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
;
; This is a rather silly example - since the result of calling the
; interface method isn't actually used. But it does illustrate how to
; use invokeinterface.
;
.method public example(Ljava/util/Enumeration;)V
.limit stack 1
.limit locals 3
; push local variable 1 (the Enumeration object)
aload_1
; now call the hasMoreElements() interface method.
invokeinterface java/util/Enumeration/hasMoreElements()Z 1
; store the integer result in local variable 2
istore_2
; done
return
.end method
.method public static main([Ljava/lang/String;)V
return
.end method

View file

@ -0,0 +1,37 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/MultiANewArray.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Example of multanewarray instruction
; -------------------------------------------------------------------------
;
; This illustrates how to use multianewarray to allocate
; an array.
;
.class public examples/MultiANewArray
.super java/lang/Object
; standard initializer
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit locals 4
.limit stack 2
;
; This allocates an array like:
;
; String s[][] = new String[2][5];
;
iconst_2
iconst_5
multianewarray [[Ljava/lang/String; 2
astore_1
return
.end method

View file

@ -0,0 +1,55 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/MultiArrays.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Examples involving multi-dimensional arrays
; -------------------------------------------------------------------------
;
; This illustrates how to use multi-dimensional arrays in the Java VM
; (though it doesn't actually do anything very interesting with the arrays.)
;
.class public examples/MultiArrays
.super java/lang/Object
; standard initializer
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit locals 4
.limit stack 5
; this is like:
; new int[2][5][]
iconst_2
iconst_5
multianewarray [[[I 2
; store the result in local variable 1
astore_1
aload_1
iconst_1
aaload ; stack now contains x[0]
astore_2 ; store the array in local variable 2
; create a new array of 50 ints and store it in x[1][1]
aload_2
iconst_1
bipush 50
newarray int
aastore
; create a new array of 60 ints and store it in x[1][2]
aload_2
iconst_2
bipush 60
newarray int
aastore
return
.end method

View file

@ -0,0 +1,41 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/NewArray.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Example of newarray
; -------------------------------------------------------------------------
;
; Example showing how to allocate an array using
; newarray.
;
.class public examples/NewArray
.super java/lang/Object
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 4
.limit locals 2
; create an array like:
;
; boolean b[] = new boolean[2]
;
; (stores it in local var 1)
iconst_2
newarray boolean
astore_1
; b[0] = true;
aload_1
iconst_0
iconst_1
bastore
return
.end method

View file

@ -0,0 +1,41 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/Switch.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Shows usage of lookupswitch and tableswitch
; -------------------------------------------------------------------------
;
; Illustrates lookupswitch and tableswitch syntax for Jasmin
;
.class public examples/Switch
.super java/lang/Object
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
.limit stack 3
iconst_1
lookupswitch
1 : Hello
2 : Goodbye
default : Foo
iconst_1
tableswitch 0
Hello
Goodbye
default : Foo
Hello:
Goodbye:
Foo:
return
.end method

View file

@ -0,0 +1,36 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/Uncaught.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Throws an exception - doesn't catch it
; -------------------------------------------------------------------------
;
; This example class contains a main() method that throws
; an exception but doesn't catch it -
;
.source Uncaught.j
.class public examples/Uncaught
.super java/lang/Object
; specify the initializer method (as for HelloWorld)
.method public <init>()V
; just call Object's initializer
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
; specify the "main" method - this throws an uncaught exception
.method public static main([Ljava/lang/String;)V
.limit stack 2
new java/lang/Exception
dup
invokenonvirtual java/lang/Exception/<init>()V
athrow
; without this the verifier might complain ...
return
.end method

View file

@ -0,0 +1,41 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/VerifyTest.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Treats an int as an object - should alert the Verifier
; -------------------------------------------------------------------------
;
; This code demonstrates the verifier at work. See also VerifyTest1.j.
;
; The main() method below tries to clone the integer 100 - this
; is clearly an error since clone() expects an Object, not an integer.
;
; If you run this with no verification on, it is likely to crash the
; interpreter. Running this with the -verify option produces a
; Verifier error.
;
; This is similar to the Java code:
;
; class VerifyTest {
; public static void main(String args[]) {
; int x = 100;
; x.clone();
; }
; }
.class public examples/VerifyTest
.super java/lang/Object
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public static main([Ljava/lang/String;)V
bipush 100
invokevirtual java/lang/Object/clone()Ljava/lang/Object;
return
.end method

View file

@ -0,0 +1,62 @@
; --- Copyright Jonathan Meyer 1996. All rights reserved. -----------------
; File: jasmin/examples/VerifyTest1.j
; Author: Jonathan Meyer, 10 July 1996
; Purpose: Trys to pull one on the verifier
; -------------------------------------------------------------------------
; This file illustrates the bytecode verifier at work - the
; code in the example() method below seems reasonable, but
; Java's bytecode verifier will fail the code because the two points leading
; to the Loop label (from the top of the method and from the ifne
; statement) have different stack states. Instead, a different approach
; must be adopted - e.g. by allocating an array, or simply writing:
;
; aconst_null
; aconst_null
; aconst_null
; aconst_null
; Note that many interpreters will run this code OK if you don't use
; a verifier. The code itself is well behaved (it doesn't trash the
; interpreter), but the approach it uses is disallowed by the verifier.
;
; Compile the example, then run it using:
;
; % java -verify VerifyTest1
; VERIFIER ERROR VerifyTest1.example()V:
; Inconsistent stack height 1 != 0
;
.class public examples/VerifyTest1
.super java/lang/Object
.method public <init>()V
aload_0
invokenonvirtual java/lang/Object/<init>()V
return
.end method
.method public example()V
.limit locals 2
.limit stack 10
; this tries to push four nulls onto the stack
; using a loop - Java's verifier will fail this program
iconst_4 ; store 4 in local variable 1 (used as a counter)
istore_1
Loop:
aconst_null ; push null onto the stack
iinc 1 -1 ; decrement local variable 4 (the counter variable)
iload_1
ifne Loop ; jump back to Loop unless the variable has reached 0
return
.end method
.method public static main([Ljava/lang/String;)V
; - do nothing : this is only to illustrate the bytecode verifier at work.
return
.end method

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

View file

@ -0,0 +1,16 @@
td { font-family: Verdana,Arial,Helvetica,sans-serif; color: #000000; font-size: 12px; line-height: 16px; }
td h1 { font-family: Tahoma; padding: 1px; padding-left: 4px; color: white; background-color: #303030; font-size: 20px; line-height: 24px; font-weight: bold; }
td h2{ font-family: Tahoma; color: #000000; font-size: 14px; line-height: 16px; font-weight: bold; }
td h3 { font-family: Tahoma; color: #000000; font-size: 12px; line-height: 16px; font-weight: bold; }
.h1 { font-family: Times; color: #000000; font-size: 18px; line-height: 20px; font-weight: bold; }
/* main text hyperlinks */
a { color: #b11; TEXT-DECORATION: underline; }
a:visited {color: #b11}
a:hover {color: #f88}
pre.code{ font-family: courier new; color: #202060; font-size: 12px; line-height: 14px;}
font.code{ font-family: courier new; color: #202060; font-size: 12px; line-height: 14px;}

View file

@ -0,0 +1,414 @@
<html>
<head>
<title>Jasmin User Guide</title>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
<table>
<tr><td width=550>
<center>
<p><img src=jasmin_icon.jpg></p>
<p>
<div class="h1">JasminXT Syntax</div>
Daniel Reynaud, Mart 2006
</p>
</center>
<h1>About This Document</h1>
This guide describes the rules and syntax used in JasminXT, the extension of
the Jasmin language in version 2.0. If you are new to Jasmin, you should
refer to the Jasmin user guide. Note that this document doesn't
explain the Java Virtual Machine itself, or give syntax notes for
every instruction known to Jasmin. See the Java Virtual Machine specification
for more information on the JVM.<p>
<h1>Why a new Jasmin language ?</h1>
<p>
Jasmin is the de-facto standard Java assembly language. It is useful to explore
the possibilities of bytecode, but it does not offer a real low level control
over the produced output. Therefore it is not suitable to generate test cases
for virtual machines or bytecode verifier. This new version of the Jasmin
language, called JasminXT, provides optional directives and other syntax
updates to have more control over the output and to stick with the latest
changes of the Java language.</p>
<p>JasminXT has been defined for the tinapoc project. The purpose of the tinapoc
project is to create a reliable Java reverse engineering toolkit. See the tinapoc
homepage for more information : <a href="http://tinapoc.sourceforge.net/">http://tinapoc.sourceforge.net/</a></p>
<h1>Summary of the new features</h1>
<p>
<b>Since 2.4 :</b><br>
<li> accept 'd'-suffix in float constant (no attempt cast to float)
<li> redesign to dynamic compiler class creation
<li> some cosmetic bugfixes
<br><br>
<b>Since 2.3 :</b><br>
<li> added 'wide'-aliases to two-face instructions
<br><br>
<b>Since 2.2 :</b><br>
<li> some bug fixes in the diagnostic
<li> added support for attribute StackMapTable (directive .stack) described in JDK1.6
<li> added keyword 'use' to directive .stack
<li> added support for \uXXXX escape sequence in the names (just as in the Java)
<li> instruction ldc_w always generates wide index
<li> changed syntaxes of the non-standard identifiers (or overloaded keywords), now it hasto be signgle quoted and can't be empty
<br><br>
<b>Since 2.1 :</b><br>
<li> some bug fixes with string and number parsing
<li> added support for \uXXXX escape sequences
<li> added support for access flags ACC_STRICT (fpstrict) and ACC_SYNTHETIC (synthetic)
<li> added signatures for local variables support
<li> several .debug directives are permitted
<li> added the invokedynamic instruction
<li> improved the syntax of the StackMap attribute (.stack directive)
<li> new command-line option -e to support different encodings
<li> added support for non-standard identifiers in double-quotes
<li> fields can now be defined on multiple lines
<li> new directives have been included : .inner, .attribute, .deprecated, .annotation
<br><br>
<b>Since 2.0 :</b><br><br>
<li>use of offsets for branch targets, local variable visibility and exception handlers. The offsets can either be absolute or relative :<br>
<pre>
goto 12 ; absolute offset : go to bytecode at offset 12
goto +5 ; relative offset : go 12 bytes forward
goto -8 ; relative offset : go 8 bytes backwards
</pre>
<li>the following access flags are now supported : ACC_ENUM, ACC_ANNOTATION, ACC_BRIDGE and ACC_VARARGS<br>
<li>the .bytecode directive has been added, to set the bytecode version in the class file.<br>
Example : <pre>.bytecode 49.0</pre><br>
<li>it is now possible to add a SourceDebugExtension attribute to the class with the following directive :<br>
<pre>.debug "some string here"</pre><br>
<li>same thing for the EnclosingMethod attribute :<br>
<pre>.enclosing method "some/package/Foo/someMethod(I)V"</pre><br>
<li>support for the Signature attribute (in the classes, methods and fields) :<br>
<pre>.signature "<my::own>Signature()"
.field myField Ljava/lang/String; signature "<my::own>Signature()"</pre><br>
<li>support for the StackMap attribute, using the .stack directive in a method definition<br>
<li>it is now possible to give the offset of an instruction before the instruction itself, like in the following code snippet :<br>
<pre>
0: aload_0
1: invokespecial java/lang/Object/<init>()V
4: aload_0
5: ldc2_w 3.14159
</pre>
</p>
<h1>JasminXT File Format</h1>
<p>
This new version is an extension of the existing Jasmin language, therefore old
Jasmin files should still compile correctly with newer versions of Jasmin.
JasminXT is supported by Jasmin 2.0 or higher. <b>Changes in Jasmin 2.4 are in bold.</b></p>
<p>
In the rest of this document, words between '[' and ']' are optional. The
syntax of a JasminXT file is the following :</p>
<pre>
&lt;jas_file&gt; {
&lt;jasmin_header&gt;
[&lt;field&gt;]*
[&lt;method&gt;]*
}
</pre>
<h1>JasminXT Header</h1>
<pre>
&lt;jasmin_header&gt; {
[.bytecode &lt;x.y&gt;]
[.source &lt;sourcefile&gt;]
&lt;class_spec&gt;
&lt;super_spec&gt;
&lt;implements&gt;
[.signature "&lt;signature&gt;"]
[.enclosing method &lt;method_name&gt;]
[.debug "&lt;debug_source_extension&gt;"]*
[.inner class [&lt;access&gt;] [&lt;name&gt;] [inner &lt;classname&gt;] [outer &lt;name&gt;]]*
[.inner interface [&lt;access&gt;] [&lt;name&gt;] [inner &lt;classname&gt;] [outer &lt;name&gt;]]*
}
example :
.bytecode 49.0
.source hello.j
.class hello
.super java/lang/Object
.signature "&lt;my::own&gt;Signature()"
.enclosing method foo/bar/Whatever/someMethod()</pre>
.debug "this string will be included in the SourceDebugExtension attribute"
.debug "this string too"
<p>The .bytecode directive sets the version of the bytecode in the class file.</p>
<p>The .signature directive, when used in the header of the Jasmin file, sets the
Signature attribute for the class (the argument is a string between double
quotes)</p>
<p>The .enclosing directive sets the EnclosingMethod attribute for the class. The
argument is a supposed to be a method name, but it can be any string between
double quotes.</p>
<p>The .debug directive sets the SourceDebugExtension attribute for the class (the
argument is also a string between double quotes)</p>
<h1>JasminXT Class, Super Class and Interfaces Definition</h1>
<pre>
&lt;class_spec&gt; {
.class &lt;access_spec&gt; &lt;class_name&gt;
}
</pre>
<p>where &lt;access_spec&gt; is any number of words taken from this list : public,
private, protected, static, final, synchronized, native, final, super,
interface, abstract, annotation, enum, bridge/volatile, transient/varargs</p>
<p>and &lt;class_name&gt; is the fully qualified internal form of the class, such as
my/package/MyClass</p><br>
<pre>
&lt;super_spec&gt; {
.super &lt;class_name&gt;
}
</pre>
<pre>
&lt;implements&gt; {
.implements &lt;class_name&gt;*
}
</pre>
<p>
The .super and .implements directives have not been modified in JasminXT<br>
The .implements directive can be repeated in order to implement multiple interfaces</p><br>
<h1>JasminXT Field Definition</h1>
<pre>
&lt;field&gt; {
.field &lt;access_spec&gt; &lt;field_name&gt; &lt;descriptor&gt; [signature &lt;signature&gt;]
[ = &lt;value&gt; ]
|
.field &lt;access_spec&gt; &lt;field_name&gt; &lt;descriptor&gt; [signature &lt;signature&gt;]
[ = &lt;value&gt; ]
[&lt;field_attribute&gt;]*
.end field
(...)
}
</pre>
<p>
If present, the Signature attribute will be set in the class file for this field with the given
quoted string as an argument.</p>
<pre>
&lt;field_attribute&gt; {
.deprecated
| .attribute &lt;name&gt; &lt;file_name&gt;
| .signature &lt;signature&gt;
| .annotation (...)
}
</pre>
(see below for the definition of the annotation and the attribute directives)
<p>examples :
<pre>.field enum myField Ljava/lang/String; signature "&lt;my::own&gt;Signature()" = "val"</pre>
<pre>.field static hello_string Ljava/lang/String;
.signature "mySignature"
.deprecated
.end field</pre>
</p>
<h1>JasminXT Method Definition</h1>
The general format of a method definition has not changed in JasminXT.
<pre>
&lt;method&gt; {
.method &lt;access_spec&gt; &lt;method_name&gt; &lt;descriptor&gt;
&lt;statement&gt;*
.end method
}
</pre>
<h1>JasminXT Method Statements</h1>
<pre>
&lt;statement&gt; {
.limit stack &lt;integer&gt;
| .limit locals &lt;integer&gt;
| .line &lt;integer&gt;
| .var &lt;var_number&gt; is &lt;var_name&gt; &lt;descriptor&gt; [signature &lt;sign&gt;] from &lt;label1&gt; to &lt;label2&gt;
| .var &lt;var_number&gt; is &lt;var_name&gt; &lt;descriptor&gt; [signature &lt;sign&gt;] from &lt;offset1&gt; to &lt;offset2&gt;
| .throws &lt;classname&gt;
| .catch &lt;classname&gt; from &lt;label1&gt; to &lt;label2&gt; using &lt;label3&gt;
| .catch &lt;classname&gt; from &lt;offset1&gt; to &lt;offset2&gt; using &lt;offset3&gt;
| .signature "&lt;signature&gt;"
| .stack
[offset {&lt;pc&gt; | &lt;label&gt;}]
[locals &lt;verification_type&gt; [&lt;verification_arg&gt;]]
(...)
[stack &lt;verification_type&gt; [&lt;verification_arg&gt;]]
(...)
.end stack
| .stack use [n] locals
(...)
.end stack
| &lt;instruction&gt; [&lt;instruction_args&gt;]
| &lt;Label&gt;:
| .deprecated
| &lt;generic&gt; ; see below for the use of generic attributes
}
</pre>
<p>
In Jasmin XT you can now use offsets instead of labels for the local variable
definitions and for the exception handlers definitions.</p>
<p>The .signature sets the Signature attribute for this method with the given
quoted string.<p>
<p>You can now also define StackMap (or StackMapTable) attributes using
the .stack directive. &lt;pc&gt; is an offset in the local bytecode array.
&lt;verification_type&gt; is one of the following keywords : Top, Integer,
Float, Long, Double, Null, UninitializedThis, Object or Uninitialized. Object
takes a &lt;classname&gt; as a parameter. Uninitialized takes an integer or a
label as a parameter. Also, jasmin allows to use "short" notation. The
'.stack use [n] locals' directive results in copy first &lt;n&gt; values from
previous .stack directive. If &lt;n&gt; is omitted, all values are copied.</p>
<p>NOTE: If bytecode version is 50 or above jasmin generates StackMapTable
attribute in accordance with specification of the new 'ClassFile Format'
edition. If bytecode version is 49 or below jasmin generate StakMap attribute
in accordance with CLDC specification.<p>
examples :
<pre>
.stack
offset 16
locals Null
locals Top
locals Object allo
stack Uninitialized 12
.end stack
.stack
; offset is not specified, the offset of the current opcode will be used
locals Null
locals Top
locals Object allo
stack Uninitialized Label0
.end stack
</pre>
<p>
This statement defines a single stack map frame. All the stack map frames
defined in a method are then aggregated and form the StackMap attribute for the
method. The last example my be wrote at the short notation as:</p>
<pre>
.stack use locals
stack Uninitialized Label0
.end stack
</pre>
<p>
<h1>JasminXT Instructions</h1>
<pre>
&lt;instruction&gt; {
[&lt;pc&gt;:] &lt;opcode&gt; [&lt;instruction_args&gt;]
}
</pre>
<p>
The main change in JasminXT is that it is now possible to put the offset of the
instruction before the opcode (the &lt;pc&gt;: statement). The pc is processed as a
label, therefore you can virtually put any number as the pc but it won't change
the actual pc of the bytecode.</p>
<p>
Another update is that it is now possible to use offsets (both relative and
absolute) as branch targets instead of labels. The offset is considered to be
relative if it begins with '$+' or '$-'.</p>
example :
<pre>
goto n ; absolute offset : go to the bytecode labelled n
goto $+n ; relative offset : go n bytes forward (from the offset of this goto)
goto $-n ; relative offset : go n bytes backwards
</pre>
<p>
If something hasn't been documented here, it means that it hasn't changed, so
you can still refer to the Jasmin <a href="guide.html">user guide</a></p>
<p>
<b>Added '_w' aliase to [adfli]-load/store, iinc and ret instructions (e.g. aload - aload_w).
Using '_w' postfix guarantees wide-form of byte-code generation</b></p>
<h1>Generic Attributes</h1>
Generic attributes are supported in class/field/method definitions as follows :
<pre>&lt;generic&gt; = {
.attribute &lt;name&gt; &lt;file_name&gt;
}</pre>
&lt;name&gt; is the name of the attribute and &lt;file_name&gt; is the name of the file containing the data of the attribute (between double quotes). If the generic attribute is in the body of the method, the following logic is used : if it is the first statement in the method, the attribute will be added as a method attribute, otherwise it will be added as a Code attribute.
<h1>Annotations</h1>
Thanks to Iouri Kharon for implementing this. Here are his explanations :<br>
<p>Added a new directive .annotation to create the AnnotationDefault,
RuntimeVisibleAnnotation, RuntimeInvisibleAnnotation,
RuntimeVisibeParameterAnnotation, RuntimeInvisibleParameterAnnotation
attributes. The directive arguments are verified to have valid values
and correct signatures.<br>
Complex (nested) annotations are supported as well as arrays of them.<br>
The generic format is:
<pre>
&lt;annotation&gt; = {
.annotation visible &lt;classname&gt;
| .annotation invisible &lt;classname>&gt;
| .annotation visibleparam &lt;paramnum&gt; &lt;classname&gt;
| .annotation invisibleparam &lt;paramnum&gt; &lt;classname&gt;
| .annotation default
........
.end annotation
Field format (except AnnotationDefault):
&lt;name&gt; &lt;signchar&gt; = &lt;value&gt;*
| &lt;name&gt; @ = .annotation
........
.end annotation
}
</pre>
AnnotationDefault supports only one field and the <name> tag is not used.
Nested annotations must be with the <name> tag and can have any number
of fields. Besides, 'empty annotation' is forbidden for AnnotationDefault.
Lastly, AnnotationDefault can be used only once for each method.
Other annotation types can be used many times and will accumulate information.</p>
<hr><address>Copyright (c) Daniel Reynaud, Mart 2006</address>
<hr>
<a href="http://jasmin.sourceforge.net">Jasmin Home</a>
</td></tr></table>
</body>
</html>

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,13 @@
10 October 2004, Jon Meyer
* Moved the jas src code into ../src/jas.
1 March 1997, Jon Meyer
* Modified JAS to use self-contained RuntimeConstants interface.
* Moved JAS classes into the Jasmin classes directory.
* Fixed bug in CatchEntry.

View file

@ -0,0 +1,109 @@
This is v0.3 of a simple Java bytecode assembler.
Quick Info:
-----------
If you want to just quickly check out things, do the following.
% java scm.driver examples/hworld.jas
This compiles an assembler script to bytecode.
% java out
This runs the resultant bytecode, which should print the
string "Hello World" 5 times.
Then read the online documentation at
http://www.blackdown.org/~kbs/jas.html
More Details:
-------------
* What is available:
A simple java bytecode assembler that can be used either as a
standalone scripting program or directly from java (through the jas
package)
* What is not available in this version:
- Error recovery in the scripting interface
- defining a tableswitch or lookupswitch instruction from the scripting
interface
* Documentation
You can leaf through the jas API in reference/jas You can look at
the list of available scripting functions from reference/scm. The
bulk of what documentation exists is online from
http://www.blackdown.org/~kbs/jas.html
UTSL, ofcourse ;-) And documentation is mostly demand-driven,
if there is interest I'll continue to expand it.
* Examples
The examples directory contains a few examples of using the
assembler with the script and directly from java. Look at the
README in this directory to see how to run them. Online
documentation contains more details.
simple.java
simple.jas
These are simple programs that create classes which
don't do anything but get initialized.
hworld.java
hworld.jas
These create bytecode that can be run standalone,
which print a string a few times.
exprcomp.java
This is a primitive compiler that does runtime
codegeneration and execution of arithmetic expressions.
exprcomp.jas
This is a primitive compiler written in jas to translate
jas arithmetic expressions to bytecode.
* Recompiling
You can recompile all classes if you wish. First remove the
jas/ and the scm/ directories under this directory. Then run the
script compile.sh in this directory.
You will probably want to then run the tests in the test directory
to make sure the basic api is functional. Look at the README in this
directory for details.
Running the scripting driver:
-----------------------------
If you are going to use the scripting language, the driver for it is
located in the class scm.driver. The magic incantation is
% java scm.driver [path to file]
If you don't give it a file name, it will try to read from stdin.
Using code from this distribution:
----------------------------------
There is exactly one class that I *use* from the sun/* package, which
is sun.tools.java.RuntimeConstants. I know of no other reasonable way
to keep in sync with the VM.
Outside of this class, (which is not present in this distribution) you
can freely use/modify/sell/dance on with hobnailed boots any or all of
this code. If you do end up using derived code and feel disinclined to
buy me a snowboard :) all I ask is that you add me to the list of
credits.
-KB-
kbs@sbktech.org
Version created: Tue Aug 21 09:50:23 PDT 1996

View file

@ -0,0 +1,52 @@
This contains three examples of using the assembler
from java and from the script
Look up http://www.blackdown.org/~kbs/jas.html for more
documentation. This only tells you how to run the examples. The
documentation is very Unix centric, I apologize.... I have not had
time to set this up on the PC's yet.
simple.java:
simple.jas:
Unexciting program that generates a do nothing class.
Go up a directory and compile simple.java. Run the program,
which generates the bytecode. Disassemble the bytecode
% (cd ..; javac -d . examples/simple.java; java simple; javap -p -c out)
Same thing, but using the script instead of java directly.
% (cd ..; java scm.driver examples/simple.jas; javap -p -c out)
hworld.java:
hworld.jas:
Print a string in a loop.
% (cd ..; javac -d . examples/hworld.java; java hworld; java out)
As before, but use script instead.
% (cd ..; java scm.driver examples/hworld.jas; java out)
exprcomp.java:
Primitive runtime expression compiler. It translates arithmetic
expressions into bytecode and loads it on the fly as a class, which
is run to get the answer. test.inp is an example of the sort of
arithmetic expressions it translates.
% (cd ..; javac -d . examples/exprcomp.java; java exprcomp examples/test.inp)
exprcomp.jas:
Primitive compiler for jas arithmetic expressions (in jas).
jas is fairly expressive, thats about the only point of this
exercise ;-) Unlike the java version, this gets written out
into a file which you'll have to run to get the results.
% (cd ..; java scm.driver examples/exprcomp.jas; java results)

View file

@ -0,0 +1,116 @@
;;; Simple arithmetic expression compiler for jas in jas.
;;;
;;; The compiler is defined in the function
;;; compile-expression
;;;
;;; use as (for instance)
;;; (compile-expression (quote (+ (* 2 (+ 1 3)) 1)))
;;;
;;; This will generate a standalone program called results.class
;;; Run the bytecode interpreter on it as:
;;;
;;; % java results
;;;
;;; which will print the result of the expression
(define compile-expression
(lambda (expr)
(real-compile-expression expr)
(dump-code)))
;; The fun part...
(define real-compile-expression
(lambda (expr)
(cond
((num? expr)
(compile-number expr))
(1 (progn
(real-compile-expression (get-op1 expr))
(real-compile-expression (get-op2 expr))
(compile-op (get-op expr))
(set! cur-stack-height (- cur-stack-height 1)))))))
;; Ah well. Back to boring bookkeeping.
(define compile-number
(lambda (num)
(append-insn (bipush num))
(set! cur-stack-height (+ 1 cur-stack-height))
(cond
((< max-stack-height cur-stack-height)
(set! max-stack-height cur-stack-height)))))
(define compile-op
(lambda (op)
(cond
((eq? op (quote +)) (append-insn (iadd)))
((eq? op (quote -)) (append-insn (isub)))
((eq? op (quote *)) (append-insn (imul)))
((eq? op (quote /)) (append-insn (idiv))))))
(define get-op1
(lambda (expr) (car (cdr expr))))
(define get-op2
(lambda (expr) (car (cdr (cdr expr)))))
(define get-op
(lambda (expr) (car expr)))
(define append-insn
(lambda (insn)
(jas-code-addinsn my-code insn)))
(define cur-stack-height 1)
(define max-stack-height 1)
(define my-code (make-code))
(define my-init-code (make-code))
; define the main() portion,
; and the call to print out the
; results.
(define append-sequence
(lambda (code-part insn-list)
(mapcar (lambda (insn) (jas-code-addinsn code-part insn))
insn-list)))
(append-sequence
my-init-code
(quote
((aload_0)
(invokenonvirtual (make-method-cpe "java/lang/Object" "<init>" "()V"))
(return))))
(define dump-code
(lambda ()
(define my-env (make-class-env))
(jas-class-setclass my-env (make-class-cpe "results"))
(jas-class-setsuperclass my-env (make-class-cpe "java/lang/Object"))
(jas-class-addmethod my-env acc-public "<init>" "()V" my-init-code ())
(append-sequence
my-code
(quote
((getstatic
(make-field-cpe "java/lang/System" "out" "Ljava/io/PrintStream;"))
(swap)
(invokevirtual (make-method-cpe
"java/io/PrintStream" "println" "(I)V"))
(return))))
(jas-code-stack-size my-code max-stack-height)
(jas-class-addmethod my-env
(| acc-public acc-static)
"main" "([Ljava/lang/String;)V" my-code ())
(jas-class-write my-env
(make-outputstream "results.class"))))
;;;
;;; example usage of compiler.
;;;
;;; run the compiled class with
;;; % java results
;;; to get the answer.
(compile-expression (quote (+ (* 2 (+ 1 3)) 1)))

View file

@ -0,0 +1,242 @@
// Primitive runtime code generation of expressions. This is a jas
// implementation of the example in Aho Sethi Ullman.
//
// You pass to it statements of the form
// a = 1*2 + 3*5;
// Only integer operations are allowed, and variables
// are magically created by using them in the LHS of a statement.
//
// You can print out the value of expressions with the println keyword:
// println(a + 10);
//
// It compiles this into a bytearray, and then loads it as
// a new class.
//
// Unfortunately, this trick cannot be used in an applet --- security
// restrictions prevent ClassLoaders from being placed on the
// stack. So much for writing regexp compilers that can do codegen instead of
// state tables.
//
// The grammar is simple, so code generation is part of the parsing
// step. Operator precedence is directly handled by the grammar.
//
// Grammar + production rules:
//
// start -> list EOF
// list -> id = expr ; { emit(istore, id.index); } list
// | println expr ; { emit(<println sequence>); } list
// | lambda
// expr -> term moreterms
// moreterms -> + term { emit(iadd) } moreterms
// | - term { emit(isub) } moreterms
// | lambda
// term -> factor morefactors
// morefactors -> * factor { emit(imul) } morefactors
// | / factor { emit(idiv) } morefactors
// | lambda
// factor -> ( expr )
// | number { emit(iconst, number.value) }
// | id { emit(iload, id.index); }
import java.util.*;
import java.io.*;
import jas.*;
import sun.tools.java.RuntimeConstants;
public class exprcomp implements RuntimeConstants
{
StreamTokenizer inp;
CodeAttr myCode;
short cur_stack_height;
short max_stack_height;
short max_vars;
Hashtable vars;
public exprcomp(StreamTokenizer inp)
throws jasError
{
inp.eolIsSignificant(false);
this.inp = inp;
myCode = new CodeAttr();
// Add initializations
myCode.addInsn(new Insn(opc_aload_0));
myCode.addInsn(new Insn(opc_invokenonvirtual,
new MethodCP("java/lang/Object",
"<init>", "()V")));
cur_stack_height = max_stack_height = 1;
vars = new Hashtable();
max_vars = 1;
}
public void write(DataOutputStream out)
throws IOException, jasError
{
ClassEnv clazz = new ClassEnv();
myCode.setStackSize(max_stack_height);
myCode.setVarSize(max_vars);
// add initializer to class
clazz.addMethod
((short) ACC_PUBLIC, "<init>", "()V", myCode, null);
clazz.setClassAccess((short) ACC_PUBLIC);
clazz.setClass(new ClassCP("results"));
clazz.setSuperClass(new ClassCP("java/lang/Object"));
clazz.write(out);
}
public void parse()
throws IOException, parseError, jasError
{
inp.nextToken();
while(inp.ttype != inp.TT_EOF)
{
if (inp.ttype != inp.TT_WORD)
{
throw new parseError("Expected an id at line " + inp.lineno());
}
if (inp.sval.equals("println"))
{
match(inp.TT_WORD);
expr();
match(';');
emit(new Insn(opc_getstatic,
new FieldCP("java/lang/System",
"out", "Ljava/io/PrintStream;")));
emit(new Insn(opc_swap));
emit(new Insn(opc_invokevirtual,
new MethodCP("java/io/PrintStream",
"println", "(I)V")));
}
else
{ // search, maybe add into var list
Integer idx;
if ((idx = (Integer) vars.get(inp.sval)) == null)
{
idx = new Integer(max_vars++);
vars.put(inp.sval.intern(), idx);
}
match(inp.TT_WORD); match('='); expr(); match(';');
emit(new Insn(opc_istore, idx.intValue()));
}
}
emit(new Insn(opc_return));
}
void expr()
throws IOException, parseError, jasError
{
term();
while (true)
{
switch(inp.ttype)
{
case '+':
match('+'); term(); emit(new Insn(opc_iadd)); break;
case '-':
match('-'); term(); emit(new Insn(opc_isub)); break;
default: return;
}
cur_stack_height--;
}
}
void term()
throws IOException, parseError, jasError
{
factor();
while (true)
{
switch(inp.ttype)
{
case '*': match('*'); factor(); emit(new Insn(opc_imul)); break;
case '/': match('/'); factor(); emit(new Insn(opc_idiv)); break;
default: return;
}
cur_stack_height --;
}
}
void factor()
throws IOException, parseError, jasError
{
switch(inp.ttype)
{
case '(': match('('); expr(); match(')'); break;
case inp.TT_NUMBER:
int val = (int)(inp.nval);
emit(new Insn(opc_bipush, (short)val));
match(inp.TT_NUMBER);
break;
case inp.TT_WORD:
Integer idx;
if ((idx = (Integer) vars.get(inp.sval)) == null)
{
throw new parseError
("Unknown variable " + inp.sval + " at line " + inp.lineno());
}
emit(new Insn(opc_iload, idx.intValue()));
match(inp.TT_WORD);
break;
default:
throw new parseError("Syntax error at line " + inp.lineno());
}
cur_stack_height++;
if (max_stack_height < cur_stack_height)
max_stack_height = cur_stack_height;
}
void match(int val)
throws IOException, parseError
{
if (inp.ttype != val)
{ throw new parseError
("line " + inp.lineno() + ": expected " + val + " but got " + inp); }
inp.nextToken();
}
void emit(Insn insn)
{
myCode.addInsn(insn);
}
public static void main(String argv[])
throws Exception
{
exprcomp compiler =
new exprcomp(new StreamTokenizer(new FileInputStream(argv[0])));
compiler.parse();
ByteArrayOutputStream data = new ByteArrayOutputStream();
compiler.write(new DataOutputStream(data));
dynaloader dl = new dynaloader(data.toByteArray());
dl.exec();
}
}
class dynaloader extends ClassLoader
{
Hashtable cache;
Class ex;
dynaloader(byte[] data)
throws ClassFormatError
{
cache = new Hashtable();
ex = defineClass(data, 0, data.length);
cache.put("results", ex);
resolveClass(ex);
}
void exec() throws Exception { ex.newInstance(); }
public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
Class c = (Class) cache.get(name);
if (c == null)
{
c = findSystemClass(name);
cache.put(name, c);
}
if (resolve) resolveClass(c);
return c;
}
}
class parseError extends Exception
{ parseError(String s) { super(s); } }

View file

@ -0,0 +1,87 @@
;; create a container
(define my-class (make-class-env))
;; specify class hierarchy
(jas-class-setaccess my-class acc-public)
(jas-class-setclass my-class (make-class-cpe "out"))
(jas-class-setsuperclass my-class (make-class-cpe "java/lang/Object"))
;; write a convenience function to append insns as a list.
(define append-code
(lambda (code-part insn-list)
(mapcar (lambda (insn) (jas-code-addinsn code-part insn))
insn-list)))
;; Define code for initializer
;;
(define init-it (make-code))
(append-code
init-it
(quote
((aload_0)
(invokenonvirtual (make-method-cpe "java/lang/Object" "<init>" "()V"))
(return))))
;; this is the code that comprises
;; the actual task, ie the code for
;; main(String argv[]).
;; print a string 5 times
(define doit (make-code))
(append-code
doit
(quote
(
; store references in local
; variables to avoid field/cp
; lookup
(getstatic
(make-field-cpe "java/lang/System" "out" "Ljava/io/PrintStream;"))
(astore_1)
(ldc (make-string-cpe "Hello World"))
(astore_2)
(bipush 5)
(istore_3) ; store loop index in var reg 3
; loop 5 times, printing out
; the string.
(make-label "loop")
; push arguments to function
; on stack and call it
(aload_1) (aload_2)
(invokevirtual
(make-method-cpe "java/io/PrintStream" "println" "(Ljava/lang/String;)V"))
; decrement loop index
(iinc 3 -1)
(iload_3)
(ifne (make-label "loop"))
(return))))
;; set stack/var size
(jas-code-stack-size doit 3)
(jas-code-var-size doit 4)
;; fill up the class with the methods
;; first the initializer.
(jas-class-addmethod my-class acc-public "<init>" "()V" init-it ())
;; define the printing code as a static main(String argv[]) method
(jas-class-addmethod my-class
(| acc-static acc-public)
"main" "([Ljava/lang/String;)V" doit ())
;; write it out.
(jas-class-write my-class (make-outputstream "out.class"))

View file

@ -0,0 +1,78 @@
import jas.*;
import java.io.*;
import sun.tools.java.RuntimeConstants;
//
// This is program that makes calls into the jas package
// to generate a class that prints a string afew times.
//
class hworld implements RuntimeConstants
{
public static void main(String argv[])
throws jasError, IOException
{
// class hierarchy
ClassEnv nclass = new ClassEnv();
nclass.setClass(new ClassCP("out"));
nclass.setSuperClass(new ClassCP("java/lang/Object"));
nclass.setClassAccess((short)ACC_PUBLIC);
// Initialization code
CodeAttr init = new CodeAttr();
init.addInsn(new Insn(opc_aload_0));
init.addInsn(new Insn(opc_invokenonvirtual,
new MethodCP("java/lang/Object", "<init>", "()V")));
init.addInsn(new Insn(opc_return));
// Actual code to print string
CodeAttr doit = new CodeAttr();
// store refs in local variables
doit.addInsn(new Insn(opc_getstatic,
new FieldCP("java/lang/System",
"out",
"Ljava/io/PrintStream;")));
doit.addInsn(new Insn(opc_astore_1));
doit.addInsn(new Insn(opc_ldc,
new StringCP("Hello World")));
doit.addInsn(new Insn(opc_astore_2));
// Loop index in var reg 3
doit.addInsn(new Insn(opc_bipush, 5));
doit.addInsn(new Insn(opc_istore_3));
// Start the loop
Label loop = new Label("loop");
doit.addInsn(loop);
doit.addInsn(new Insn(opc_aload_1));
doit.addInsn(new Insn(opc_aload_2));
doit.addInsn(new Insn(opc_invokevirtual,
new MethodCP("java/io/PrintStream",
"println",
"(Ljava/lang/String;)V")));
doit.addInsn(new IincInsn(3, -1));
doit.addInsn(new Insn(opc_iload_3));
doit.addInsn(new Insn(opc_ifne, loop));
doit.addInsn(new Insn(opc_return));
// set the right sizes for code
doit.setStackSize((short)3); doit.setVarSize((short)4);
// Add the init code to the class.
nclass.addMethod((short)ACC_PUBLIC, "<init>", "()V", init, null);
// Add the printing code
nclass.addMethod((short)(ACC_PUBLIC|ACC_STATIC), "main",
"([Ljava/lang/String;)V", doit, null);
// write it all out
nclass.write(new DataOutputStream
(new FileOutputStream("out.class")));
}
}

View file

@ -0,0 +1,30 @@
;; script to create a class that does nothing.
; make-class-env creates
; a ClassEnv object which is
; used to store information about
; an object.
(define my-class (make-class-env))
; make-code creates a code object
; which contains the body of a
; method.
(define init-code (make-code))
(jas-code-addinsn init-code
(aload_0))
(jas-code-addinsn init-code
(invokenonvirtual
(make-method-cpe "java/lang/Object" "<init>" "()V")))
(jas-code-addinsn init-code
(return))
; fill up the class with goodies
(jas-class-setsuperclass my-class (make-class-cpe "java/lang/Object"))
(jas-class-setclass my-class (make-class-cpe "out"))
(jas-class-setaccess my-class acc-public)
(jas-class-addmethod my-class acc-public "<init>" "()V" init-code ())
; and write it all out
(jas-class-write my-class (make-outputstream "out.class"))

View file

@ -0,0 +1,45 @@
import jas.*;
import java.io.*;
import sun.tools.java.RuntimeConstants;
//
// This is program that makes calls into the jas package
// to generate a class that does nothing at all.
//
class simple implements RuntimeConstants
{
public static void main(String argv[])
throws jasError, IOException
{
// CodeAttr's contain the body of
// a method.
CodeAttr init = new CodeAttr();
init.addInsn(new Insn(opc_aload_0));
init.addInsn(new Insn(opc_invokenonvirtual,
new MethodCP("java/lang/Object", "<init>", "()V")));
init.addInsn(new Insn(opc_return));
// ClassEnv's are used as a container
// to hold all information about a class.
ClassEnv nclass = new ClassEnv();
nclass.setClass(new ClassCP("out"));
nclass.setSuperClass(new ClassCP("java/lang/Object"));
// Add the init code to the class.
nclass.addMethod((short)ACC_PUBLIC, "<init>", "()V", init, null);
// write it all out
nclass.write(new DataOutputStream
(new FileOutputStream("out.class")));
}
}

View file

@ -0,0 +1,8 @@
a = 10;
println a;
b = a + 5;
println (b);
println(a*b +2);

View file

@ -0,0 +1,16 @@
This is a start of a basic set of tests intended to exercise the API
functions available in the jas and scm packages. It is not complete by
any means.
all.java tries to touch as much of the jas API as it can, generating a
non functional class called regress.class. all.jas does
something similar, but for the scm package.
Once the jas and scm packages are compiled, do this:
% (cd ..; javac -d . tests/all.java; java all; cmp regress.class tests/regress.class)
% (cd ..; java scm.driver tests/all.jas; cmp scmregress.class tests/scmregress.class)
If both these complete silently, you are in good shape. Otherwise,
mail me a bug report and enough details for me to replicate it :)

View file

@ -0,0 +1,72 @@
(define my-env (make-class-env))
(jas-class-addcpe my-env (make-ascii-cpe "fubar"))
(jas-class-addcpe my-env (make-class-cpe "java/lang/Number"))
(jas-class-addcpe my-env (make-double-cpe 2.0))
(jas-class-addcpe my-env
(make-field-cpe "java/lang/System" "out" "Ljava/io/PrintStream;"))
(jas-class-addcpe my-env (make-float-cpe 2.0))
(jas-class-addcpe my-env (make-integer-cpe 2))
(jas-class-addcpe my-env
(make-interface-cpe "java/lang/Runnable" "run" "()V"))
(jas-class-addcpe my-env (make-long-cpe 2))
(jas-class-addcpe my-env
(make-method-cpe "java/lang/Thread" "run" "()V"))
(jas-class-addcpe my-env
(make-name-type-cpe "sdfsdf" "Ljava/lang/Object;"))
(jas-class-addcpe my-env (make-string-cpe "sdf"))
(jas-class-addfield my-env
(make-field
acc-public (make-ascii-cpe "someIntVar") (make-ascii-cpe "I") ()))
(jas-class-addfield my-env
(make-field
(| acc-public acc-static) (make-ascii-cpe "finalInt")
(make-ascii-cpe "I") (make-const (make-integer-cpe 10.2))))
(jas-class-addinterface my-env (make-class-cpe "java/lang/Runnable"))
(jas-class-setclass my-env (make-class-cpe "scmregress"))
(jas-class-setsuperclass my-env (make-class-cpe "java/lang/Object"))
(jas-class-setaccess my-env acc-public)
(define my-code (make-code))
(jas-code-addinsn my-code (return))
(jas-code-addinsn my-code (astore 5))
(jas-code-addinsn my-code (make-label "First label"))
(jas-code-addinsn my-code (jsr (make-label "First label")))
(define saved-label (make-label "second_label"))
(jas-code-addinsn my-code saved-label)
(jas-code-addinsn my-code (ldc_w (make-string-cpe "sdfsdf")))
(jas-code-addinsn my-code (iinc 2 -2))
(jas-code-addinsn my-code
(invokeinterface
(make-class-cpe "java/lang/Number") 1))
(jas-code-addinsn my-code (multianewarray (make-class-cpe "java/lang/Double")
3))
(define ctb (make-catchtable))
(jas-add-catch-entry ctb (make-catch-entry
(make-label "First label")
saved-label
saved-label
(make-class-cpe "java/lang/Exception")))
(jas-add-catch-entry ctb (make-catch-entry
(make-label "First label")
saved-label
saved-label
(make-class-cpe "java/lang/Error")))
(jas-set-catchtable my-code ctb)
(jas-code-stack-size my-code 100)
(jas-code-var-size my-code 100)
(define my-except (make-exception))
(jas-exception-add my-except (make-class-cpe "java/io/IOException"))
(jas-exception-add my-except (make-class-cpe "java/lang/Error"))
(jas-class-addmethod my-env
acc-public
"somemethod"
"(I)V"
my-code
my-except)
(jas-class-write my-env (make-outputstream "scmregress.class"))

View file

@ -0,0 +1,155 @@
// Simply try
// to access as much of
// the API as possible.
import jas.*;
import java.io.*;
import sun.tools.java.RuntimeConstants;
public class all implements RuntimeConstants
{
public static void main(String argv[])
throws Exception
{
ClassEnv c = new ClassEnv();
// Adding CP Items directly
c.addCPItem(new AsciiCP("fubar"));
c.addCPItem(new ClassCP("java/lang/Number"));
c.addCPItem(new DoubleCP(2.0));
c.addCPItem(new FieldCP("java/lang/System",
"out",
"Ljava/io/PrintStream;"));
c.addCPItem(new FloatCP((float)(2.0)));
c.addCPItem(new IntegerCP(2));
c.addCPItem(new InterfaceCP("java/lang/Runnable",
"run",
"()V"));
c.addCPItem(new LongCP(2));
c.addCPItem(new MethodCP("java/lang/Thread",
"run",
"()V"));
c.addCPItem(new NameTypeCP("sdfsdf", "Ljava/lang/Object;"));
c.addCPItem(new StringCP("sdf"));
// Add fields, creating variables
c.addField(new Var((short) ACC_PUBLIC,
new AsciiCP("someIntvar"),
new AsciiCP("I"),
null));
c.addField(new Var((short)(ACC_PUBLIC|ACC_STATIC|ACC_FINAL),
new AsciiCP("finalInt"),
new AsciiCP("I"),
new ConstAttr(new IntegerCP(10))));
// Check if I can add interfaces
c.addInterface(new ClassCP("java/lang/Runnable"));
c.setClass(new ClassCP("regress"));
c.setSuperClass(new ClassCP("java/lang/Object"));
c.setClassAccess((short) ACC_PUBLIC);
// Creating code.
CodeAttr code = new CodeAttr();
// add instructions of various
// operand types.
// No operands
code.addInsn(new Insn(opc_return));
// one arg operands
code.addInsn(new Insn(opc_astore, 5));
// one arg arguments with wide operand
code.addInsn(new Insn(opc_dstore, 256));
code.addInsn(new Insn(opc_istore, 2576));
// Add a label
code.addInsn(new Label("First label"));
// refer back to it
code.addInsn(new Insn(opc_jsr,
new Label("First label")));
// add another label
code.addInsn(new Label("second_label"));
// insn with CP argument
code.addInsn(new Insn(opc_ldc_w, new StringCP("sdfsdf")));
// the "special" instructions
code.addInsn(new IincInsn(2, -2));
// wider version check
code.addInsn(new IincInsn(1234, 2));
code.addInsn(new IincInsn(3, -200));
code.addInsn(new InvokeinterfaceInsn(new ClassCP("java/lang/Number"), 1));
code.addInsn(new MultiarrayInsn(new ClassCP("java/lang/Double"), 3));
Label woo[] = new Label[3];
woo[0] = new Label("First label");
woo[1] = new Label("second_label");
woo[2] = new Label("second_label");
code.addInsn(new TableswitchInsn(0, 2, woo[0], woo));
int m[] = new int[3];
m[0] = 11;
m[1] = 15;
m[2] = -1;
code.addInsn(new LookupswitchInsn(woo[0], m, woo));
// make a catchtable
Catchtable ctb = new Catchtable();
// add a couple of entries
ctb.addEntry(new Label("First label"),
new Label("second_label"),
new Label("second_label"),
new ClassCP("java/lang/Exception"));
ctb.addEntry(new Label("First label"),
new Label("second_label"),
new Label("second_label"),
new ClassCP("java/lang/Error"));
code.setCatchtable(ctb);
code.setStackSize((short)100);
code.setVarSize((short)500);
// Add some line table info
LineTableAttr ln = new LineTableAttr();
ln.addEntry(woo[0], 234);
ln.addEntry(woo[1], 245);
ln.addEntry(woo[2], 22);
code.setLineTable(ln);
// Add a generic attr to a method
String foo = "sldkfj sdlfkj";
byte dat[] = new byte[foo.length()];
foo.getBytes(0, dat.length, dat, 0);
code.addGenericAttr(new GenericAttr("strangeAttr", dat));
// Also adding local varinfo
LocalVarTableAttr lv = new LocalVarTableAttr();
lv.addEntry(new LocalVarEntry(woo[0], woo[2], "fakevar", "I", 22));
lv.addEntry(new LocalVarEntry(woo[1], woo[1], "morefa", "()V", 10));
code.setLocalVarTable(lv);
// check out add method, also
// adding a throws exception for
// good measure
ExceptAttr ex = new ExceptAttr();
ex.addException(new ClassCP("java/io/IOException"));
ex.addException(new ClassCP("java/lang/Error"));
c.addMethod((short) ACC_PUBLIC,
"fubarmethod",
"()V",
code,
ex);
// Add a source file attribute
c.setSource(new SourceAttr("all.java"));
// Add some more generic attribute
c.addGenericAttr(new GenericAttr("blahAttr", dat));
c.write(new DataOutputStream(new FileOutputStream("regress.class")));
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -0,0 +1,100 @@
#!/bin/csh
#
# JavaCup install and test script
# Scott Hudson 8/31/95
#
# Last revision 1/7/96 (for v0.9d)
#
echo
echo "===================================="
echo "Installing and testing JavaCup v0.9d"
echo "===================================="
echo
# check for this directory in CLASSPATH
#
set cwd = `pwd`
if ($CLASSPATH !~ "*$cwd*") then
echo " "
echo "WARNING:"
echo "WARNING: The current directory does not appear in your CLASSPATH"
echo "WARNING: it will be added for this install/test only"
echo "WARNING:"
echo " "
set CLASSPATH = $CLASSPATH':'$cwd
echo "CLASSPATH now set to "
echo $CLASSPATH
endif
# change to the demo directory
#
echo " "
echo "changing to simple_calc subdirectory..."
echo "cd simple_calc"
cd simple_calc
# remove old copies of parser.java and sym.java
#
echo " "
echo "removing any old copies of parser.java and sym.java..."
echo "rm -f parser.java sym.java"
rm -f parser.java sym.java
# compile java_cup and run it against the demo program
# the -cs (for "checksource") option here will force the
# java_cup and java_cup.runtime source to be compiled prior
# to running it.
#
echo " "
echo "compiling java_cup then generating demo program..."
echo "java -cs java_cup.Main < parser.cup"
java -cs java_cup.Main < parser.cup
# make sure parser.java and sym.java now exist
#
if ( ! -e parser.java) then
echo " "
echo "ERROR: for some reason parser.java was not created"
echo "ERROR: install was not successful"
exit 1
endif
if ( ! -e sym.java) then
echo " "
echo "ERROR: for some reason sym.java was not created"
echo "ERROR: install was not successful"
exit 1
endif
# run the demo
# again, the -cs option will cause compilation of all the parts
# of the demo program (including parser.java and sym.java that
# should have been generated in the previous step).
#
echo "removing old test results..."
echo "rm -f test_results"
rm -f test_results
echo " "
echo "executing the demo program..."
echo "echo '2+2;' | java -cs Main >& test_results"
echo '2+2;' | java -cs Main >& test_results
# compare with standard results
#
set res = `tail -1 test_results`
if ("$res" !~ "= 4") then
echo "ERROR: test program produced the wrong results"
echo "ERROR: output was:"
cat test_results
echo "ERROR: install was not successful"
rm -f test_results
exit 2
endif
# all is well
#
rm -f test_results
echo " "
echo "=============================="
echo "Install and test was successful"
echo "=============================="
exit 0

View file

@ -0,0 +1,5 @@
Jasmin use of Java Cup
The source code for JavaCup, as it is used in the Jasmin distribution, has been moved to ../src/java_cup.

View file

@ -0,0 +1,44 @@
This directory contains the Java CUP v0.9d release in source form. You should
find the following files and subdirectories in this release:
README This file.
java_cup A subdirectory containing Java CUP and runtime sources.
javacup.logo.gif A logo image used by the manual.
manual.html A user's manual in HTML format.
simple_calc A subdirectory containing a small demo and test application.
INSTALL A shell script to install and test the system
To install the release, copy the contents of this directory (if you haven't
done so already) into a "classes" directory accessible to the java interpreter
(i.e., a directory that is listed in the colon separated list of directories
in your CLASSPATH environment variable).
Once files have been copied to an appropriate location, you should be able to
both compile and test the system by executing the INSTALL shell script
(sorry, but non Unix users are still on their own for this release
-- zip archive and directions for Win95 users coming soon).
Again, be sure that you have placed these sources in a directory listed in
your CLASSPATH environment variable (or changed your CLASSPATH to include
this directory). The INSTALL script will warn you if this is not the case.
A manual page that explains the operation and use of the system can be found
in manual.html and from the Java CUP home page mentioned below.
This is an alpha-test release of the Java CUP system and is designed to run
under the JDK-beta2 Java compiler. Bug reports regarding the installation
process or the system as a whole can be sent to java-cup@cc.gatech.edu.
The Java CUP home page where the latest information regarding Java CUP can be
found (e.g., new releases) is:
http://www.cc.gatech.edu/gvu/people/Faculty/hudson/java_cup/home.html
Enjoy,
Scott Hudson
Graphics, Visualization, and Usability Center
Georgia Institute of Technology
Last updated: 1/7/96 [SEH]

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View file

@ -0,0 +1,883 @@
<html><head>
<title>Java(tm) CUP User's Manual</title>
</head><body>
<hr>
<img src="java_cup.logo.new.gif" alt="Java CUP Logo Image">
<hr>
<h1>Java(tm) CUP User's Manual</h1>
<h3><a href="http://www.cc.gatech.edu/gvu/people/Faculty/Scott.E.Hudson.html">
Scott E. Hudson</a><br>
<a href="http://www.cc.gatech.edu/gvu/gvutop.html">
Graphics Visualization and Usability Center</a><br>
<a href="http://www.gatech.edu/TechHome.html">
Georgia Institute of Technology</a><br>
<i>January 1996</i> (v0.9d release)</h3>
<hr>
<h3>Table of Contents</h3>
<dl compact>
<dt> 1. <dd> <a href="#intro">Introduction and Example</a>
<dt> 2. <dd> <a href="#spec">Specification Syntax</a>
<dt> 3. <dd> <a href="#running">Running Java CUP</a>
<dt> 4. <dd> <a href="#parser">Customizing the Parser</a>
<dt> 5. <dd> <a href="#errors">Error Recovery</a>
<dt> 6. <dd> <a href="#conclusion">Conclusion</a>
<dt> <dd> <a href="#refs">References</a>
<dt> A. <dd> <a href="#appendixa">Grammar for Java CUP Specification Files</a>
<dt> B. <dd> <a href="#appendixb">A Very Simple Example Scanner</a>
</dl>
<a name=intro>
<h3>1. Introduction and Example</h3></a>
This manual describes the basic operation and use of the
Java<a href="#trademark">(tm)</a>
Based Constructor of Useful Parsers (Java CUP for short).
Java CUP is a system for generating LALR parsers from simple specifications.
It serves the same role as the widely used program YACC
<a href="#YACCref">[1]</a> and in fact offers most of the features of YACC.
However, Java CUP is written in Java, uses specifications including embedded
Java code, and produces parsers which are implemented in Java.<p>
Although covering all aspect of the Java CUP system, this manual is relatively
brief, assumes you have at least a little bit of knowledge of LR parsing,
and preferably have a bit of experience with a program such as YACC.
A number of compiler construction textbooks (such as
<a href="#dragonbook">[2</a>,<a href="#crafting">3]</a>) cover this material,
and discuss the YACC system (which is quite similar to this one) as a
specific example. <p>
Using Java CUP involves creating a simple specifications based on the
grammar for which a parser is needed, along with construction of a
scanner capable of breaking characters up into meaningful tokens (such
as keywords, numbers, and special symbols).<p>
As a simple example, consider a
system for evaluating simple arithmetic expressions over integers.
This system would read expressions from standard input (each terminated
with a semicolon), evaluate them, and print the result on standard output.
A grammar for the input to such a system might look like: <pre>
expr_list ::= expr_list expr_part | expr_part
expr_part ::= expr ';'
expr ::= expr '+' term | expr '-' term | term
term ::= term '*' factor | term '/' factor | term '%' factor | factor
factor ::= number | '-' expr | '(' expr ')'
</pre>
To specify a parser based on this grammar, our first step is to identify and
name the set of terminal symbols that will appear on input, and the set of
non terminal symbols. In this case, the non terminals are:
<pre><tt> expr_list, expr_part, expr, term,</tt> and <tt>factor</tt>.</pre>
For terminal names we might choose:
<pre><tt> SEMI, PLUS, MINUS, TIMES, DIVIDE, MOD, NUMBER, LPAREN,</tt> and <tt>RPAREN</tt></pre>
Based on these namings we can construct a small Java CUP specification
as follows:<br>
<hr>
<pre><tt>// Java CUP specification for a simple expression evaluator (no actions)
import java_cup.runtime.*;
/* Preliminaries to set up and use the scanner. */
init with {: scanner.init(); :};
scan with {: return scanner.next_token(); :};
/* Terminals (tokens returned by the scanner). */
terminal token SEMI, PLUS, MINUS, TIMES, DIVIDE, MOD, LPAREN, RPAREN;
terminal int_token NUMBER;
/* Non terminals */
non terminal symbol expr_list, expr_part;
non terminal int_token expr, term, factor;
/* The grammar */
expr_list ::= expr_list expr_part |
expr_part;
expr_part ::= expr SEMI;
expr ::= expr PLUS term |
expr MINUS term |
term;
term ::= term TIMES factor |
term DIVIDE factor |
term MOD factor |
factor;
factor ::= NUMBER |
MINUS factor |
LPAREN expr LPAREN;
</tt></pre>
<hr><br>
We will consider each part of the specification syntax in detail later.
However, here we can quickly see that the specification contains three
main parts. The first part provides preliminary and miscellaneous declarations
to specify how the parser is to be generated, and supply parts of the
runtime code. In this case we indicate that the <tt>java_cup.runtime</tt>
classes should be imported, then supply a small bit of initialization code,
and some code for invoking the scanner to retrieve the next input token.
The second part of the specification declares terminals and non terminals,
and associates object classes with each. In this case, we declare our terminals
as being represented at runtime by two object types: <tt>token</tt> and
<tt>int_token</tt> (which are supplied as part of the Java CUP runtime system),
while various non terminals are represented by objects of types <tt>symbol</tt>
and <tt>int_token</tt> (again supplied from the runtime system). The final
part of the specification contains the grammar.<p>
To produce a parser from this specification we use the Java CUP generator.
If this specification were stored in a file <tt>parser.cup</tt>, then
(on a Unix system at least) we might invoke Java CUP using a command like:
<pre><tt> java java_cup.Main &lt; parser.cup</tt> </pre>
In this case, the system will produce two Java source files containing
parts of the generated parser: <tt>sym.java</tt> and <tt>parser.java</tt>.
As you might expect, these two files contain declarations for the classes
<tt>sym</tt> and <tt>parser</tt>. The <tt>sym</tt> class contains a series of
constant declarations, one for each terminal symbol. This is typically used
by the scanner to refer to symbols (e.g. with code such as
"<tt>return new token(sym.SEMI);</tt>" ). The <tt>parser</tt> class
implements the parser itself.<p>
The specification above, while constructing a full parser, does not perform
any semantic actions -- it will only indicate success or failure of a parse.
To calculate and print values of each expression, we must embed Java
code within the parser to carry out actions at various points. In Java CUP,
actions are contained in <i>code strings</i> which are surrounded by delimiters
of the form <tt>{:</tt> and <tt>:}</tt> (we can see examples of this in the
<tt>init with</tt> and <tt>scan with</tt> clauses above). In general, the
system records all characters within the delimiters, but does not try to check
that it contains valid Java code.<p>
A more complete Java CUP specification for our example system (with actions
embedded at various points in the grammar) is shown below:<br>
<hr>
<pre><tt>// Java CUP specification for a simple expression evaluator (w/ actions)
import java_cup.runtime.*;
/* Preliminaries to set up and use the scanner. */
init with {: scanner.init(); :};
scan with {: return scanner.next_token(); :};
/* Terminals (tokens returned by the scanner). */
terminal token SEMI, PLUS, MINUS, TIMES, DIVIDE, MOD, LPAREN, RPAREN;
terminal int_token NUMBER;
/* Non terminals */
non terminal symbol expr_list, expr_part;
non terminal int_token expr, term, factor;
/* The grammar */
expr_list ::= expr_list expr_part
|
expr_part;
expr_part ::= expr:e
{: System.out.println("= " + e.int_val); :}
SEMI
;
expr ::= expr:e1 PLUS term:e2
{: RESULT.int_val = e1.int_val + e2.int_val; :}
|
expr:e1 MINUS term:e2
{: RESULT.int_val = e1.int_val - e2.int_val; :}
|
term:e1
{: RESULT.int_val = e1.int_val; :}
;
term ::= term:e1 TIMES factor:e2
{: RESULT.int_val = e1.int_val * e2.int_val; :}
|
term:e1 DIVIDE factor:e2
{: RESULT.int_val = e1.int_val / e2.int_val; :}
|
term:e1 MOD factor:e2
{: RESULT.int_val = e1.int_val % e2.int_val; :}
|
factor:e
{: RESULT.int_val = e.int_val; :}
;
factor ::= NUMBER:n
{: RESULT.int_val = n.int_val; :}
|
MINUS factor:e
{: RESULT.int_val = -e.int_val; :}
|
LPAREN expr:e RPAREN
{: RESULT.int_val = e.int_val; :}
;
</tt></pre>
<hr><br>
Here we can see several changes. Most importantly, code to be executed at
various points in the parse is included inside code strings delimited by
<tt>{:</tt> and <tt>:}</tt>. In addition, labels have been placed on various
symbols in the right hand side of productions. For example in:<br>
<pre> expr ::= expr:e1 PLUS term:e2
{: RESULT.int_val = e1.int_val + e2.int_val; :}
</pre>
the non terminal <tt>expr</tt> has been labeled with <tt>e1</tt>, while
<tt>term</tt> has been labeled with <tt>e2</tt>. The left hand side
symbol of each production is always implicitly labeled as <tt>RESULT</tt>.<p>
Each symbol appearing in a production is represented at runtime by an
object (on the parse stack). These labels allow code embedded in a
production to refer to these objects. Since <tt>expr</tt> and <tt>term</tt>
were both declared as <tt>int_token</tt>, they are both represented by
an object of class <tt>int_token</tt>. These objects are created
as the result of matching some other production. The code in that production
fills in various fields of its result object, which are in turn used here to
fill in a new result object, and so on. Overall this is a very common
form of syntax directed translation related to attribute grammars and
discussed at length in compiler construction textbooks such as
<a href="#dragonbook">[2</a>,<a href="#crafting">3]</a>.
<p>
In our specific example, the <tt>int_token</tt> class includes an
<tt>int_val</tt> field which stores an <tt>int</tt> value. We use this
field to compute the value of the expression from its component parts.
In the production above, we compute the <tt>int_val</tt> field of the
left hand side symbol (i.e. <tt>RESULT</tt>) as the sum of the values
computed by the <tt>expr</tt> and <tt>term</tt> parts making up this
expression. That value in turn may be combined with other to compute a
final result.<p>
The final step in creating a working parser is to create a <i>scanner</i> (also
known as a <i>lexical analyzer</i> or simply a <i>lexer</i>). This routine is
responsible for reading individual characters, removing things things like
white space and comments, recognizing which terminal symbols from the
grammar each group of characters represents, then returning token objects
representing these symbols to the parser. Example code for a workable (if
not elegant or efficient) scanner for our example system can be found in
<a href="#appendixb">Appendix B</a>.<p>
Like the very simple one given in Appendix B, all scanners need to return
objects which are instances of <tt>java_cup.runtime.token</tt> (or one of
its subclasses). The runtime system predefines three such classes:
<tt>token</tt> which contains no specific information beyond the token
type (and some internal information used by the parser), <tt>int_token</tt>
which also records a single <tt>int</tt> value, and <tt>str_token</tt> which
records a single string value. <p>
The code contained in the <tt>init with</tt> clause of the specification
will be executed before any tokens are requested. Each token will be
requested using whatever code is found in the <tt>scan with</tt> clause.
Beyond this, the exact form the scanner takes is up to you. <p>
In the <a href="#spec">next section</a> a more detailed and formal
explanation of all parts of a Java CUP specification will be given.
<a href="#running">Section 3</a> describes options for running the
Java CUP system. <a href="#parser">Section 4</a> discusses the details
of how to customize a Java CUP parser, while <a href="#errors">Section 5</a>
considers error recovery. Finally, <a href="#conclusion">Section 6</a>
provides a conclusion.
<a name="spec">
<h3>2. Specification Syntax</h3></a>
Now that we have seen a small example, we present a complete description of all
parts of a Java CUP specification. A specification has four sections with
a total of eight specific parts (however, most of these are optional).
A specification consists of:
<ul>
<li> <a href="#package_spec">package and import specifications</a>,
<li> <a href="#code_part">user code components</a>,
<li> <a href="#symbol_list">symbol (terminal and non-terminal) lists</a>, and
<li> <a href="#production_list">the grammar</a>.
</ul>
Each of these parts must appear in the order presented here. (A complete
grammar for the specification language is given in
<a href="#appendixa">Appendix A</a>.) The particulars of each part of
the specification are described in the subsections below.<p>
<h5><a name="package_spec">Package and Import Specifications</a></h5>
A specification begins with optional <tt>package</tt> and <tt>import</tt>
declarations. These have the same syntax, and play the same
role, as the package and import declarations found in a normal Java program.
A package declaration is of the form:
<pre><tt> package <i>name</i>;</tt></pre>
where name <tt><i>name</i></tt> is a Java package identifier, possibly in
several parts separated by ".". In general, Java CUP employs Java lexical
conventions. So for example, both styles of Java comments are supported,
and identifiers are constructed beginning with a letter, dollar
sign ($), or underscore (_), which can then be followed by zero or more
letters, numbers, dollar signs, and underscores.<p>
After an optional <tt>package</tt> declaration, there can be zero or more
<tt>import</tt> declarations. As in a Java program these have the form:
<pre><tt> import <i>package_name.class_name</i>;</tt>
</pre>
or
<pre><tt> import <i>package_name</i>.*;</tt>
</pre>
The package declaration indicates what package the <tt>sym</tt> and
<tt>parser</tt> classes that are generated by the system will be in.
Any import declarations that appear in the specification will also appear
in the source file for the <tt>parser</tt> class allowing various names from
that package to be used directly in user supplied action code.
<h5><a name="code_part">User Code Components</a></h5>
Following the optional <tt>package</tt> and <tt>import</tt> declarations
are a series of optional declarations that allow user code to be included
as part of the generated parser (see <a href="#parser">Section 4</a> for a
full description of how the parser uses this code). As a part of the parser
file, a separate non-public class to contain all embedded user actions is
produced. The first <tt>action code</tt> declaration section allows code to
be included in this class. Routines and variables for use by the code
embedded in the grammar would normally be placed in this section (a typical
example might be symbol table manipulation routines). This declaration takes
the form:
<pre><tt> action code {: ... :};</tt>
</pre>
where <tt>{: ... :}</tt> is a code string whose contents will be placed
directly within the <tt>action class</tt> class declaration.<p>
After the <tt>action code</tt> declaration is an optional
<tt>parser code</tt> declaration. This declaration allows methods and
variable to be placed directly within the generated parser class.
Although this is less common, it can be helpful when customizing the
parser -- it is possible for example, to include scanning methods inside
the parser and/or override the default error reporting routines. This
declaration is very similar to the <tt>action code</tt> declaration and
takes the form:
<pre><tt> parser code {: ... :};</tt>
</pre>
Again, code from the code string is placed directly into the generated parser
class definition.<p>
Next in the specification is the optional <tt>init</tt> declaration
which has the form:
<pre><tt> init with {: ... :};</tt></pre>
This declaration provides code that will be executed by the parser
before it asks for the first token. Typically, this is used to initialize
the scanner as well as various tables and other data structures that might
be needed by semantic actions. In this case, the code given in the code
string forms the body of a <tt>void</tt> method inside the <tt>parser</tt>
class.<p>
The final (optional) user code section of the specification indicates how
the parser should ask for the next token from the scanner. This has the
form:
<pre><tt> scan with {: ... :};</tt></pre>
As with the <tt>init</tt> clause, the contents of the code string forms
the body of a method in the generated parser. However, in this case
the method returns an object of type <tt>java_cup.runtime.token</tt>.
Consequently the code found in the <tt>scan with</tt> clause should
return such a value.<p>
<h5><a name="symbol_list">Symbol Lists</a></h5>
Following user supplied code comes the first required part of the
specification: the symbol lists. These declarations are responsible
for naming and supplying a type for each terminal and non-terminal
symbol that appears in the grammar. As indicated above, each terminal
and non-terminal symbol is represented at runtime with an object. In
the case of terminals, these are returned by the scanner and placed on
the parse stack. In the case of non terminals these replace a series
of symbol objects on the parse stack whenever the right hand side of
some production is recognized. In order to tell the parser which object
types should be used for which symbol, <tt>terminal</tt> and
<tt>non terminal</tt> declarations are used. These take the forms:
<pre><tt> terminal <i>classname</i> <i>name1, name2,</i> ...;</tt>
</pre>
and
<pre><tt> non terminal <i>classname</i> <i>name1, name2,</i> ...;</tt>
</pre>
where <tt><i>classname</i></tt> can be a multiple part name separated with
"."s. Since the parser uses these objects for internal bookkeeping, the
classes used for non terminal symbols must be a subclass of
<tt>java_cup.runtime.symbol</tt>. Similarly, the classes used for terminal
symbols must be a subclass of <tt>java_cup.runtime.token</tt> (note that
<tt>java_cup.runtime.token</tt> is itself a subclass of
<tt>java_cup.runtime.symbol</tt>).
<h5><a name="production_list">The Grammar</a></h5>
The final section of a Java CUP declaration provides the grammar. This
section optionally starts with a declaration of the form:
<pre><tt> start with <i>nonterminal</i>;</tt>
</pre>
This indicates which non terminal is the <i>start</i> or <i>goal</i>
non terminal for parsing. If a start non terminal is not explicitly
declared, then the non terminal on the left hand side of the first
production will be used.<p>
The grammar itself follows the optional <tt>start</tt> declaration. Each
production in the grammar has a left hand side non terminal followed by
the symbol "<tt>::=</tt>", which is then followed by a series of zero or more
actions, terminal, or non terminal symbols, and terminated with a semicolon (;).
Each symbol on the right hand side can optionally be labeled with a name.
Label names appear after the symbol name separated by a colon (:). Label
names must be unique within the production, and can be used within action
code to refer to the runtime object that represents the symbol.
If there are several productions for the same non terminal they may be
declared together. In this case the productions start with the non terminal
and "<tt>::=</tt>". This is followed by multiple right hand sides each
separated by a bar (|). The full set of productions is then terminated by a
semicolon.<p>
Actions appear in the right hand side as code strings (e.g., Java code inside
<tt>{:</tt> ... <tt>:}</tt> delimiters). These are executed by the parser
at the point when the portion of the production to the left of the
action has been recognized. (Note that the scanner will have returned the
token one past the point of the action since the parser needs this extra
<i>lookahead</i> token for recognition.)
<a name="running">
<h3>3. Running Java CUP</h3></a>
As mentioned above, Java CUP is written in Java. To invoke it, one needs
to use the Java interpreter to invoke the static method
<tt>java_cup.Main()</tt>, passing an array of strings containing options.
Assuming a Unix machine, the simplest way to do this is typically to invoke it
directly from the command line with a command such as:
<pre><tt> java java_cup.Main <i>options</i> &lt; <i>inputfile</i></tt></pre>
Once running, Java CUP expects to find a specification file on standard input
and produces two Java source files as output. <p>
In addition to the specification file, Java CUP's behavior can also be changed
by passing various options to it. Legal options include:
<dl>
<dt><tt>-package</tt> <i>name</i>
<dd>Specify that the <tt>parser</tt> and <tt>sym</tt> classes are to be
placed in the named package. By default, no package specification
is put in the generated code (hence the classes default to the special
"unnamed" package).
<dt><tt>-parser</tt> <i>name</i>
<dd>Output parser and action code into a file (and class) with the given
name instead of the default of "<tt>parser</tt>".
<dt><tt>-symbols</tt> <i>name</i>
<dd>Output the symbol constant code into a class with the given
name instead of the default of "<tt>sym</tt>".
<dt><tt>-nonterms</tt>
<dd>Place constants for non terminals into the symbol constant class.
The parser does not need these symbol constants, so they are not normally
output. However, it can be very helpful to refer to these constants
when debugging a generated parser.
<dt><tt>-expect</tt> <i>number</i>
<dd>During parser construction the system may detect that an ambiguous
situation would occur at runtime. This is called a <i>conflict</i>.
In general, the parser may be unable to decide whether to <i>shift</i>
(read another symbol) or <i>reduce</i> (replace the recognized right
hand side of a production with its left hand side). This is called a
<i>shift/reduce conflict</i>. Similarly, the parser may not be able
to decide between reduction with two different productions. This is
called a <i>reduce/reduce conflict</i>. Normally, if one or more of
these conflicts occur, parser generation is aborted. However, in
certain carefully considered cases it may be advantageous to
arbitrarily break such a conflict. In this case Java CUP uses YACC
convention and resolves shift/reduce conflicts by shifting, and
reduce/reduce conflicts using the "highest priority" production (the
one declared first in the specification). In order to enable automatic
breaking of conflicts the <tt>-expect</tt> option must be given
indicating exactly how many conflicts are expected.
<dt><tt>-compact_red</tt>
<dd>Including this option enables a table compaction optimization involving
reductions. In particular, it allows the most common reduce entry in
each row of the parse action table to be used as the default for that
row. This typically saves considerable room in the tables, which can
grow to be very large. This optimization has the effect of replacing
all error entries in a row with the default reduce entry. While this
may sound dangerous, if not down right incorrect, it turns out that this
does not affect the correctness of the parser. In particular, some
changes of this type are inherent in LALR parsers (when compared to
canonical LR parsers), and the resulting parsers will still never
read past the first token at which the error could be detected.
The parser can, however, make extra erroneous reduces before detecting
the error, so this can degrade the parser's ability to do
<a href="#errors">error recovery</a>.
(Refer to reference [2] pp. 244-247 or reference [3] pp. 190-194 for a
complete explanation of this compaction technique.) <br><br>
<i>Special note</i>: at the time of this writing the standard
javac compiler had a bug which caused it to produce corrupted
class files when very large statically initialized arrays (i.e., large
parse tables) are used. Consequently, if you have a large grammar, you
may be <i>forced</i> to use this option in order to create tables
that are small enough to compile correctly.
<dt><tt>-nowarn</tt>
<dd>This options causes all warning messages (as opposed to error messages)
produced by the system to be suppressed.
<dt><tt>-nosummary</tt>
<dd>Normally, the system prints a summary listing such things as the
number of terminals, non terminals, parse states, etc. at the end of
its run. This option suppresses that summary.
<dt><tt>-progress</tt>
<dd>This option causes the system to print short messages indicating its
progress through various parts of the parser generation process.
<dt><tt>-dump_grammar</tt>
<dt><tt>-dump_states</tt>
<dt><tt>-dump_tables</tt>
<dt><tt>-dump</tt>
<dd> These options cause the system to produce a human readable dump of
the grammar, the constructed parse states (often needed to resolve
parse conflicts), and the parse tables (rarely needed), respectively.
The <tt>-dump</tt> option can be used to produce all of these dumps.
<dt><tt>-time</tt>
<dd>This option adds detailed timing statistics to the normal summary of
results. This is normally of great interest only to maintainers of
the system itself.
<dt><tt>-debug</tt>
<dd>This option produces voluminous internal debugging information about
the system as it runs. This is normally of interest only to maintainers
of the system itself.
</dl>
<a name="parser">
<h3>4. Customizing the Parser</h3></a>
Each generated parser consists of three generated classes. The
<tt>sym</tt> class (which can be renamed using the <tt>-symbols</tt>
option) simply contains a series of <tt>int</tt> constants,
one for each terminal. Non terminals are also include if the <tt>-nonterms</tt>
option is given. The source file for the <tt>parser</tt> class (which can
be renamed using the <tt>-parser</tt> option) actually contains two
class definitions, the public <tt>parser</tt> class that implements the
actual parser, and another non-public class (called <tt>CUP$action</tt>) which
encapsulates all user actions contained in the grammar, as well as code from
the <tt>action code</tt> declaration. In addition to user supplied code, this
class contains one method: <tt>CUP$do_action</tt> which consists of a large
switch statement for selecting and executing various fragments of user
supplied action code. In general, all names beginning with the prefix of
<tt>CUP$</tt> are reserved for internal uses by Java CUP generated code. <p>
The <tt>parser</tt> class contains the actual generated parser. It is
a subclass of <tt>java_cup.runtime.lr_parser</tt> which implements a
general table driven framework for an LR parser. The generated <tt>parser</tt>
class provides a series of tables for use by the general framework.
Three tables are provided:
<dl compact>
<dt>the production table
<dd>provides the symbol number of the left hand side non terminal, along with
the length of the right hand side, for each production in the grammar,
<dt>the action table
<dd>indicates what action (shift, reduce, or error) is to be taken on each
lookahead symbol when encountered in each state, and
<dt>the reduce-goto table
<dd>indicates which state to shift to after reduces (under each non-terminal
from each state).
</dl>
(Note that the action and reduce-goto tables are not stored as simple arrays,
but use a compacted "list" structure to save a significant amount of space.
See comments the runtime system source code for details.)<p>
Beyond the parse tables, generated (or inherited) code provides a series
of methods that can be used to customize the generated parser. Some of these
methods are supplied by code found in part of the specification and can
be customized directly in that fashion. The others are provided by the
<tt>lr_parser</tt> base class and can be overridden with new versions (via
the <tt>parser code</tt> declaration) to customize the system. Methods
available for customization include:
<dl compact>
<dt><tt>public void user_init()</tt>
<dd>This method is called by the parser prior to asking for the first token
from the scanner. The body of this method contains the code from the
<tt>init with</tt> clause of the the specification.
<dt><tt>public java_cup.runtime.token scan()</tt>
<dd>This method encapsulates the scanner and is called each time a new token is
needed by the parser. The body of this method is supplied by the
<tt>scan with</tt> clause of the specification.
<dt><tt> public void report_error(String message, Object info)</tt>
<dd>This method should be called whenever an error message is to be issued. In
the default implementation of this method, the first parameter provides
the text of a message which is printed on <tt>System.err</tt>
and the second parameter is simply ignored. It is very typical to
override this method in order to provide a more sophisticated error
reporting mechanism.
<dt><tt>public void report_fatal_error(String message, Object info)</tt>
<dd>This method should be called whenever a non-recoverable error occurs. It
responds by calling <tt>report_error()</tt>, then aborts parsing
by calling the parser method <tt>done_parsing()</tt>, and finally
throws an exception. (In general <tt>done_parsing()</tt> should be called
at any point that parsing needs to be terminated early).
<dt><tt>public void syntax_error(token cur_token)</tt>
<dd>This method is called by the parser as soon as a syntax error is detected
(but before error recovery is attempted). In the default implementation it
calls: <tt>report_error("Syntax error", null);</tt>.
<dt><tt>public void unrecovered_syntax_error(token cur_token)</tt>
<dd>This method is called by the parser if it is unable to recover from a
syntax error. In the default implementation it calls:
<tt>report_fatal_error("Couldn't repair and continue parse", null);</tt>.
<dt><tt> protected int error_sync_size()</tt>
<dd>This method is called by the parser to determine how many tokens it must
successfully parse in order to consider an error recovery successful.
The default implementation returns 3. Values below 2 are not recommended.
See the section on <a href="#errors">error recovery</a> for details.
</dl>
Parsing itself is performed by the method <tt>public void parse()</tt>.
This method starts by getting references to each of the parse tables,
then initializes a <tt>CUP$action</tt> object (by calling
<tt>protected void init_actions()</tt>). Next it calls <tt>user_init()</tt>,
then fetches the first lookahead token with a call to <tt>scan()</tt>.
Finally, it begins parsing. Parsing continues until <tt>done_parsing()</tt>
is called (this is done automatically, for example, when the parser accepts).<p>
In addition to the normal parser, the runtime system also provides a debugging
version of the parser. This operates in exactly the same way as the normal
parser, but prints debugging messages (by calling
<tt>public void debug_message(String mess)</tt> whose default implementation
prints a message to <tt>System.err</tt>).<p>
Based on these routines, invocation of a Java CUP parser is typically done
with code such as:
<pre>
/* create a parsing object */
parser parse_obj = new parser();
/* open input files, etc. here */
try {
if (do_debug_parse)
parser_obj.debug_parse();
else
parser_obj.parse();
} catch (Exception e) {
/* do cleanup here -- possibly rethrow e */
} finally {
/* do close out here */
}
</pre>
<a name="errors">
<h3>5. Error Recovery</h3></a>
A final important aspect of building parsers with Java CUP is
support for syntactic error recovery. Java CUP uses the same
error recovery mechanisms as YACC. In particular, it supports
a special error symbol (denoted simply as <tt>error</tt>).
This symbol plays the role of a special non terminal which, instead of
being defined by productions, instead matches an erroneous input
sequence.<p>
The error symbol only comes into play if a syntax error is
detected. If a syntax error is detected then the parser tries to replace
some portion of the input token stream with <tt>error</tt> and then
continue parsing. For example, we might have productions such as:
<pre><tt> stmt ::= expr SEMI | while_stmt SEMI | if_stmt SEMI | ... |
error SEMI
;</tt></pre>
This indicates that if none of the normal productions for <tt>stmt</tt> can
be matched by the input, then a syntax error should be declared, and recovery
should be made by skipping erroneous tokens (equivalent to matching and
replacing them with <tt>error</tt>) up to a point at which the parse can
be continued with a semicolon (and additional context that legally follows a
statement). An error is considered to be recovered from if and only if a
sufficient number of tokens past the <tt>error</tt> symbol can be successfully
parsed. (The number of tokens required is determined by the
<tt>error_sync_size()</tt> method of the parser and defaults to 3). <p>
Specifically, the parser first looks for the closest state to the top
of the parse stack that has an outgoing transition under
<tt>error</tt>. This generally corresponds to working from
productions that represent more detailed constructs (such as a specific
kind of statement) up to productions that represent more general or
enclosing constructs (such as the general production for all
statements or a production representing a whole section of declarations)
until we get to a place where an error recovery production
has been provided for. Once the parser is placed into a configuration
that has an immediate error recovery (by popping the stack to the first
such state), the parser begins skipping tokens to find a point at
which the parse can be continued. After discarding each token, the
parser attempts to parse ahead in the input (without executing any
embedded semantic actions). If the parser can successfully parse past
the required number of tokens, then the input is backed up to the point
of recovery and the parse is resumed normally (executing all actions).
If the parse cannot be continued far enough, then another token is
discarded and the parser again tries to parse ahead. If the end of
input is reached without making a successful recovery (or there was no
suitable error recovery state found on the parse stack to begin with)
then error recovery fails.
<a name="conclusion">
<h3>6. Conclusion</h3></a>
This manual has briefly described the Java CUP LALR parser generation system.
Java CUP is designed to fill the same role as the well known YACC parser
generator system, but is written in and operates entirely with Java code
rather than C or C++. Additional details on the operation of the system can
be found in the parser generator and runtime source code. See the Java CUP
home page below for access to the API documentation for the system and its
runtime.<p>
This document covers the system as it stands at the time of its fourth alpha
release (v0.9d). Check the Java CUP home page:
<a href="http://www.cc.gatech.edu/gvu/people/Faculty/hudson/java_cup/home.html">
http://www.cc.gatech.edu/gvu/people/Faculty/hudson/java_cup/home.html</a>
for the latest release information, instructions for downloading the
system, and additional news about the system. Bug reports and other
comments for the developers can be sent to
<a href="mailto:java-cup@cc.gatech.edu"> java-cup@cc.gatech.edu</a><p>
Java CUP was originally written by
<a href="http://www.cc.gatech.edu/gvu/people/Faculty/Scott.E.Hudson.html">
Scott Hudson</a>, in August of 1995.<p>
<a name="refs">
<h3>References</h3></a>
<dl compact>
<dt><a name = "YACCref">[1]</a>
<dd>S. C. Johnson,
"YACC -- Yet Another Compiler Compiler",
CS Technical Report #32,
Bell Telephone Laboratories,
Murray Hill, NJ,
1975.
<dt><a name = "dragonbook">[2]</a>
<dd>A. Aho, R. Sethi, and J. Ullman,
<i>Compilers: Principles, Techniques, and Tools</i>,
Addison-Wesley Publishing,
Reading, MA,
1986.
<dt><a name = "crafting">[3]</a>
<dd>C. Fischer, and R. LeBlanc,
<i>Crafting a Compiler with C</i>,
Benjamin/Cummings Publishing,
Redwood City, CA,
1991.
</dl>
<h3><a name="appendixa">
Appendix A. Grammar for Java CUP Specification Files</a></h3>
<hr><br>
<pre><tt>java_cup_spec ::= package_spec import_list code_part init_code
scan_code symbol_list start_spec production_list
package_spec ::= PACKAGE multipart_id SEMI | empty
import_list ::= import_list import_spec | empty
import_spec ::= IMPORT import_id SEMI
code_part ::= action_code_part parser_code_part
action_code_part ::= ACTION CODE CODE_STRING SEMI | empty
parser_code_part ::= PARSER CODE CODE_STRING SEMI | empty
init_code ::= INIT WITH CODE_STRING SEMI | empty
scan_code ::= SCAN WITH CODE_STRING SEMI | empty
symbol_list ::= symbol_list symbol | symbol
symbol ::= TERMINAL type_id term_name_list SEMI |
NON TERMINAL type_id non_term_name_list SEMI
term_name_list ::= term_name_list COMMA new_term_id | new_term_id
non_term_name_list ::= non_term_name_list COMMA new_non_term_id |
new_non_term_id
start_spec ::= START WITH nt_id SEMI | empty
production_list ::= production_list production | production
production ::= nt_id COLON_COLON_EQUALS rhs_list SEMI
rhs_list ::= rhs_list BAR rhs | rhs
rhs ::= prod_part_list
prod_part_list ::= prod_part_list prod_part | empty
prod_part ::= symbol_id opt_label | CODE_STRING
opt_label ::= COLON label_id | empty
multipart_id ::= multipart_id DOT ID | ID
import_id ::= multipart_id DOT STAR | multipart_id
type_id ::= multipart_id
new_term_id ::= ID
new_non_term_id ::= ID
nt_id ::= ID
symbol_id ::= ID
label_id ::= ID
</tt></pre>
<hr><p><p>
<h3><a name = "appendixb">Appendix B. A Very Simple Example Scanner<a></h3>
<hr><br>
<pre>
<tt>// Simple Example Scanner Class
import java_cup.runtime.*;
public class scanner {
/* single lookahead character */
protected static int next_char;
/* advance input by one character */
protected static void advance() { next_char = System.in.read(); }
/* initialize the scanner */
public static void init() { advance(); }
/* recognize and return the next complete token */
public static token next_token()
{
for (;;)
switch (next_char)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* parse a decimal integer */
int i_val = 0;
do {
i_val = i_val * 10 + (next_char - '0');
advance();
} while (next_char >= '0' && next_char <= '9');
return new int_token(sym.NUMBER, i_val);
case ';': advance(); return new token(sym.SEMI);
case '+': advance(); return new token(sym.PLUS);
case '-': advance(); return new token(sym.MINUS);
case '*': advance(); return new token(sym.TIMES);
case '/': advance(); return new token(sym.DIVIDE);
case '%': advance(); return new token(sym.MOD);
case '(': advance(); return new token(sym.LPAREN);
case ')': advance(); return new token(sym.RPAREN);
case -1: return new token(sym.EOF);
default:
/* in this simple scanner we just ignore everything else */
advance();
break;
}
}
};
</tt></pre>
<hr>
<a name="trademark">
Java and HotJava are
trademarks of <a href="http://www.sun.com/">Sun Microsystems, Inc.</a>,
and refer to Sun's Java programming language and HotJava browser
technologies.
Java CUP is not sponsored by or affiliated with Sun Microsystems, Inc.
</a>
<hr><p><p>
</body></html>

View file

@ -0,0 +1,27 @@
public class Main {
public static void main(String argv[])
{
try {
/* allocate a parser object */
parser parse_obj = new parser();
/* prompt the user */
System.out.println("Reading expressions from standard input...");
/* deterimine if we doing debug or normal parse, and do it */
if (argv.length >= 1 && argv[0].equals("-debug"))
{
parse_obj.debug_parse();
}
else
{
parse_obj.parse();
}
} catch (java.lang.Exception ex) {
System.err.println("Exception: " + ex.getMessage());
ex.printStackTrace();
System.exit(-1);
}
}
};

View file

@ -0,0 +1,58 @@
// JavaCup specification for a simple expression evaluator (w/ actions)
import java_cup.runtime.*;
/* Preliminaries to set up and use the scanner. */
init with {: scanner.init(); :};
scan with {: return scanner.next_token(); :};
/* Terminals (tokens returned by the scanner). */
terminal token SEMI, PLUS, MINUS, TIMES, DIVIDE, MOD, LPAREN, RPAREN;
terminal int_token NUMBER;
/* Non terminals */
non terminal symbol expr_list, expr_part;
non terminal int_token expr, term, factor;
/* The grammar */
expr_list ::= expr_list expr_part
|
expr_part;
expr_part ::= expr:e
{: System.out.println("= " + e.int_val); :}
SEMI
;
expr ::= expr:e1 PLUS term:e2
{: RESULT.int_val = e1.int_val + e2.int_val; :}
|
expr:e1 MINUS term:e2
{: RESULT.int_val = e1.int_val - e2.int_val; :}
|
term:e1
{: RESULT.int_val = e1.int_val; :}
;
term ::= term:e1 TIMES factor:e2
{: RESULT.int_val = e1.int_val * e2.int_val; :}
|
term:e1 DIVIDE factor:e2
{: RESULT.int_val = e1.int_val / e2.int_val; :}
|
term:e1 MOD factor:e2
{: RESULT.int_val = e1.int_val % e2.int_val; :}
|
factor:e
{: RESULT.int_val = e.int_val; :}
;
factor ::= NUMBER:n
{: RESULT.int_val = n.int_val; :}
|
MINUS factor:e
{: RESULT.int_val = -e.int_val; :}
|
LPAREN expr:e RPAREN
{: RESULT.int_val = e.int_val; :}
;

View file

@ -0,0 +1,287 @@
//----------------------------------------------------
// The following code was generated by Java(tm) CUP v0.9d
// Sun Jan 07 17:10:11 EST 1996
//----------------------------------------------------
import java_cup.runtime.*;
public class parser extends java_cup.runtime.lr_parser {
/** constructor */
public parser() {super();}
/** production table */
protected static final short _production_table[][] = {
{1, 2}, {0, 2}, {1, 1}, {6, 0}, {2, 3},
{3, 3}, {3, 3}, {3, 1}, {4, 3}, {4, 3},
{4, 3}, {4, 1}, {5, 1}, {5, 2}, {5, 3}
};
/** access to production table */
public short[][] production_table() {return _production_table;}
/** parse action table */
protected static final short[][] _action_table = {
/*0*/{4,2,8,9,10,4,-1,0},
/*1*/{4,2,8,9,10,4,-1,0},
/*2*/{2,-12,3,-12,4,-12,5,-12,6,-12,7,-12,9,-12,-1,0},
/*3*/{2,-13,3,-13,4,-13,5,-13,6,-13,7,-13,9,-13,-1,0},
/*4*/{0,-3,4,-3,8,-3,10,-3,-1,0},
/*5*/{2,-4,3,13,4,11,-1,0},
/*6*/{0,23,4,2,8,9,10,4,-1,0},
/*7*/{2,-8,3,-8,4,-8,5,16,6,17,7,15,9,-8,-1,0},
/*8*/{4,2,8,9,10,4,-1,0},
/*9*/{3,13,4,11,9,12,-1,0},
/*10*/{4,2,8,9,10,4,-1,0},
/*11*/{2,-15,3,-15,4,-15,5,-15,6,-15,7,-15,9,-15,-1,0},
/*12*/{4,2,8,9,10,4,-1,0},
/*13*/{2,-6,3,-6,4,-6,5,16,6,17,7,15,9,-6,-1,0},
/*14*/{4,2,8,9,10,4,-1,0},
/*15*/{4,2,8,9,10,4,-1,0},
/*16*/{4,2,8,9,10,4,-1,0},
/*17*/{2,-10,3,-10,4,-10,5,-10,6,-10,7,-10,9,-10,-1,0},
/*18*/{2,-9,3,-9,4,-9,5,-9,6,-9,7,-9,9,-9,-1,0},
/*19*/{2,-11,3,-11,4,-11,5,-11,6,-11,7,-11,9,-11,-1,0},
/*20*/{2,-7,3,-7,4,-7,5,16,6,17,7,15,9,-7,-1,0},
/*21*/{0,-1,4,-1,8,-1,10,-1,-1,0},
/*22*/{0,-2,-1,0},
/*23*/{2,25,-1,0},
/*24*/{0,-5,4,-5,8,-5,10,-5,-1,0},
/*25*/{2,-14,3,-14,4,-14,5,-14,6,-14,7,-14,9,-14,-1,0},
};
/** access to parse action table */
public short[][] action_table() {return _action_table;}
/** reduce_goto table */
protected static final short[][] _reduce_table = {
/*0*/{1,6,2,4,3,5,4,7,5,2,-1,-1},
/*1*/{5,25,-1,-1},
/*2*/{-1,-1},
/*3*/{-1,-1},
/*4*/{-1,-1},
/*5*/{6,23,-1,-1},
/*6*/{2,21,3,5,4,7,5,2,-1,-1},
/*7*/{-1,-1},
/*8*/{3,9,4,7,5,2,-1,-1},
/*9*/{-1,-1},
/*10*/{4,20,5,2,-1,-1},
/*11*/{-1,-1},
/*12*/{4,13,5,2,-1,-1},
/*13*/{-1,-1},
/*14*/{5,19,-1,-1},
/*15*/{5,18,-1,-1},
/*16*/{5,17,-1,-1},
/*17*/{-1,-1},
/*18*/{-1,-1},
/*19*/{-1,-1},
/*20*/{-1,-1},
/*21*/{-1,-1},
/*22*/{-1,-1},
/*23*/{-1,-1},
/*24*/{-1,-1},
/*25*/{-1,-1},
};
/** access to reduce_goto table */
public short[][] reduce_table() {return _reduce_table;}
/** instance of action encapsulation class */
protected CUP$actions action_obj;
/** action encapsulation object initializer */
protected void init_actions()
{
action_obj = new CUP$actions();
}
/** invoke a user supplied parse action */
public java_cup.runtime.symbol do_action(
int act_num,
java_cup.runtime.lr_parser parser,
java.util.Stack stack,
int top)
throws java.lang.Exception
{
/* call code in generated class */
return action_obj.CUP$do_action(act_num, parser, stack, top);
}
/** start state */
public int start_state() {return 0;}
/** start production */
public int start_production() {return 1;}
/** EOF symbol index */
public int EOF_sym() {return 0;}
/** error symbol index */
public int error_sym() {return 1;}
/** user initialization */
public void user_init() throws java.lang.Exception
{
scanner.init();
}
/** scan to get the next token */
public java_cup.runtime.token scan()
throws java.lang.Exception
{
return scanner.next_token();
}
};
/** JavaCup generated class to encapsulate user supplied action code.*/
class CUP$actions {
/** Constructor */
CUP$actions() { }
/** Method with the actual generated action code. */
public final java_cup.runtime.symbol CUP$do_action(
int CUP$act_num,
java_cup.runtime.lr_parser CUP$parser,
java.util.Stack CUP$stack,
int CUP$top)
throws java.lang.Exception
{
/* object for return from actions */
java_cup.runtime.symbol CUP$result;
/* select the action based on the action number */
switch (CUP$act_num)
{
/*. . . . . . . . . . . . . . . . . . . .*/
case 14: // factor ::= LPAREN expr RPAREN
{
CUP$result = new int_token(/*factor*/5);
((int_token)CUP$result).int_val = (/*e*/(int_token)CUP$stack.elementAt(CUP$top-1)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 13: // factor ::= MINUS factor
{
CUP$result = new int_token(/*factor*/5);
((int_token)CUP$result).int_val = -(/*e*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 12: // factor ::= NUMBER
{
CUP$result = new int_token(/*factor*/5);
((int_token)CUP$result).int_val = (/*n*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 11: // term ::= factor
{
CUP$result = new int_token(/*term*/4);
((int_token)CUP$result).int_val = (/*e*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 10: // term ::= term MOD factor
{
CUP$result = new int_token(/*term*/4);
((int_token)CUP$result).int_val = (/*e1*/(int_token)CUP$stack.elementAt(CUP$top-2)).int_val % (/*e2*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 9: // term ::= term DIVIDE factor
{
CUP$result = new int_token(/*term*/4);
((int_token)CUP$result).int_val = (/*e1*/(int_token)CUP$stack.elementAt(CUP$top-2)).int_val / (/*e2*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 8: // term ::= term TIMES factor
{
CUP$result = new int_token(/*term*/4);
((int_token)CUP$result).int_val = (/*e1*/(int_token)CUP$stack.elementAt(CUP$top-2)).int_val * (/*e2*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 7: // expr ::= term
{
CUP$result = new int_token(/*expr*/3);
((int_token)CUP$result).int_val = (/*e1*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 6: // expr ::= expr MINUS term
{
CUP$result = new int_token(/*expr*/3);
((int_token)CUP$result).int_val = (/*e1*/(int_token)CUP$stack.elementAt(CUP$top-2)).int_val - (/*e2*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 5: // expr ::= expr PLUS term
{
CUP$result = new int_token(/*expr*/3);
((int_token)CUP$result).int_val = (/*e1*/(int_token)CUP$stack.elementAt(CUP$top-2)).int_val + (/*e2*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val;
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 4: // expr_part ::= expr NT$0 SEMI
{
CUP$result = new symbol(/*expr_part*/2);
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 3: // NT$0 ::=
{
CUP$result = new java_cup.runtime.token(/*NT$0*/6);
System.out.println("= " + (/*e*/(int_token)CUP$stack.elementAt(CUP$top-0)).int_val);
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 2: // expr_list ::= expr_part
{
CUP$result = new symbol(/*expr_list*/1);
}
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 1: // $START ::= expr_list EOF
{
CUP$result = new java_cup.runtime.token(/*$START*/0);
}
/* ACCEPT */
CUP$parser.done_parsing();
return CUP$result;
/*. . . . . . . . . . . . . . . . . . . .*/
case 0: // expr_list ::= expr_list expr_part
{
CUP$result = new symbol(/*expr_list*/1);
}
return CUP$result;
/* . . . . . .*/
default:
throw new Exception(
"Invalid action number found in internal parse table");
}
}
};

View file

@ -0,0 +1,51 @@
// Simple Example Scanner Class
import java_cup.runtime.*;
public class scanner {
/* single lookahead character */
protected static int next_char;
/* advance input by one character */
protected static void advance() throws java.io.IOException
{
next_char = System.in.read();
}
/* initialize the scanner */
public static void init() throws java.io.IOException { advance(); }
/* recognize and return the next complete token */
public static token next_token() throws java.io.IOException
{
for (;;)
switch (next_char)
{
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
/* parse a decimal integer */
int i_val = 0;
do {
i_val = i_val * 10 + (next_char - '0');
advance();
} while (next_char >= '0' && next_char <= '9');
return new int_token(sym.NUMBER, i_val);
case ';': advance(); return new token(sym.SEMI);
case '+': advance(); return new token(sym.PLUS);
case '-': advance(); return new token(sym.MINUS);
case '*': advance(); return new token(sym.TIMES);
case '/': advance(); return new token(sym.DIVIDE);
case '%': advance(); return new token(sym.MOD);
case '(': advance(); return new token(sym.LPAREN);
case ')': advance(); return new token(sym.RPAREN);
case -1: return new token(sym.EOF);
default:
/* in this simple scanner we just ignore everything else */
advance();
break;
}
}
};

View file

@ -0,0 +1,22 @@
//----------------------------------------------------
// The following code was generated by Java(tm) CUP v0.9d
// Sun Jan 07 17:10:10 EST 1996
//----------------------------------------------------
/** JavaCup generated class containing symbol constants. */
public class sym {
/* terminals */
static final int SEMI = 2;
static final int EOF = 0;
static final int DIVIDE = 6;
static final int NUMBER = 10;
static final int error = 1;
static final int MINUS = 4;
static final int TIMES = 5;
static final int LPAREN = 8;
static final int RPAREN = 9;
static final int MOD = 7;
static final int PLUS = 3;
};

View file

@ -0,0 +1,212 @@
This is the license for Ant, the open source build system that Jasmin uses.
This license applies only to ./lib/ant.jar
You can learn more about Ant and download the files from http://jakarta.apache.org/ant/
- Jon Meyer
-------------------------------------------------------------------------------
/*
* Apache License
* Version 2.0, January 2004
* http://www.apache.org/licenses/
*
* TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
*
* 1. Definitions.
*
* "License" shall mean the terms and conditions for use, reproduction,
* and distribution as defined by Sections 1 through 9 of this document.
*
* "Licensor" shall mean the copyright owner or entity authorized by
* the copyright owner that is granting the License.
*
* "Legal Entity" shall mean the union of the acting entity and all
* other entities that control, are controlled by, or are under common
* control with that entity. For the purposes of this definition,
* "control" means (i) the power, direct or indirect, to cause the
* direction or management of such entity, whether by contract or
* otherwise, or (ii) ownership of fifty percent (50%) or more of the
* outstanding shares, or (iii) beneficial ownership of such entity.
*
* "You" (or "Your") shall mean an individual or Legal Entity
* exercising permissions granted by this License.
*
* "Source" form shall mean the preferred form for making modifications,
* including but not limited to software source code, documentation
* source, and configuration files.
*
* "Object" form shall mean any form resulting from mechanical
* transformation or translation of a Source form, including but
* not limited to compiled object code, generated documentation,
* and conversions to other media types.
*
* "Work" shall mean the work of authorship, whether in Source or
* Object form, made available under the License, as indicated by a
* copyright notice that is included in or attached to the work
* (an example is provided in the Appendix below).
*
* "Derivative Works" shall mean any work, whether in Source or Object
* form, that is based on (or derived from) the Work and for which the
* editorial revisions, annotations, elaborations, or other modifications
* represent, as a whole, an original work of authorship. For the purposes
* of this License, Derivative Works shall not include works that remain
* separable from, or merely link (or bind by name) to the interfaces of,
* the Work and Derivative Works thereof.
*
* "Contribution" shall mean any work of authorship, including
* the original version of the Work and any modifications or additions
* to that Work or Derivative Works thereof, that is intentionally
* submitted to Licensor for inclusion in the Work by the copyright owner
* or by an individual or Legal Entity authorized to submit on behalf of
* the copyright owner. For the purposes of this definition, "submitted"
* means any form of electronic, verbal, or written communication sent
* to the Licensor or its representatives, including but not limited to
* communication on electronic mailing lists, source code control systems,
* and issue tracking systems that are managed by, or on behalf of, the
* Licensor for the purpose of discussing and improving the Work, but
* excluding communication that is conspicuously marked or otherwise
* designated in writing by the copyright owner as "Not a Contribution."
*
* "Contributor" shall mean Licensor and any individual or Legal Entity
* on behalf of whom a Contribution has been received by Licensor and
* subsequently incorporated within the Work.
*
* 2. Grant of Copyright License. Subject to the terms and conditions of
* this License, each Contributor hereby grants to You a perpetual,
* worldwide, non-exclusive, no-charge, royalty-free, irrevocable
* copyright license to reproduce, prepare Derivative Works of,
* publicly display, publicly perform, sublicense, and distribute the
* Work and such Derivative Works in Source or Object form.
*
* 3. Grant of Patent License. Subject to the terms and conditions of
* this License, each Contributor hereby grants to You a perpetual,
* worldwide, non-exclusive, no-charge, royalty-free, irrevocable
* (except as stated in this section) patent license to make, have made,
* use, offer to sell, sell, import, and otherwise transfer the Work,
* where such license applies only to those patent claims licensable
* by such Contributor that are necessarily infringed by their
* Contribution(s) alone or by combination of their Contribution(s)
* with the Work to which such Contribution(s) was submitted. If You
* institute patent litigation against any entity (including a
* cross-claim or counterclaim in a lawsuit) alleging that the Work
* or a Contribution incorporated within the Work constitutes direct
* or contributory patent infringement, then any patent licenses
* granted to You under this License for that Work shall terminate
* as of the date such litigation is filed.
*
* 4. Redistribution. You may reproduce and distribute copies of the
* Work or Derivative Works thereof in any medium, with or without
* modifications, and in Source or Object form, provided that You
* meet the following conditions:
*
* (a) You must give any other recipients of the Work or
* Derivative Works a copy of this License; and
*
* (b) You must cause any modified files to carry prominent notices
* stating that You changed the files; and
*
* (c) You must retain, in the Source form of any Derivative Works
* that You distribute, all copyright, patent, trademark, and
* attribution notices from the Source form of the Work,
* excluding those notices that do not pertain to any part of
* the Derivative Works; and
*
* (d) If the Work includes a "NOTICE" text file as part of its
* distribution, then any Derivative Works that You distribute must
* include a readable copy of the attribution notices contained
* within such NOTICE file, excluding those notices that do not
* pertain to any part of the Derivative Works, in at least one
* of the following places: within a NOTICE text file distributed
* as part of the Derivative Works; within the Source form or
* documentation, if provided along with the Derivative Works; or,
* within a display generated by the Derivative Works, if and
* wherever such third-party notices normally appear. The contents
* of the NOTICE file are for informational purposes only and
* do not modify the License. You may add Your own attribution
* notices within Derivative Works that You distribute, alongside
* or as an addendum to the NOTICE text from the Work, provided
* that such additional attribution notices cannot be construed
* as modifying the License.
*
* You may add Your own copyright statement to Your modifications and
* may provide additional or different license terms and conditions
* for use, reproduction, or distribution of Your modifications, or
* for any such Derivative Works as a whole, provided Your use,
* reproduction, and distribution of the Work otherwise complies with
* the conditions stated in this License.
*
* 5. Submission of Contributions. Unless You explicitly state otherwise,
* any Contribution intentionally submitted for inclusion in the Work
* by You to the Licensor shall be under the terms and conditions of
* this License, without any additional terms or conditions.
* Notwithstanding the above, nothing herein shall supersede or modify
* the terms of any separate license agreement you may have executed
* with Licensor regarding such Contributions.
*
* 6. Trademarks. This License does not grant permission to use the trade
* names, trademarks, service marks, or product names of the Licensor,
* except as required for reasonable and customary use in describing the
* origin of the Work and reproducing the content of the NOTICE file.
*
* 7. Disclaimer of Warranty. Unless required by applicable law or
* agreed to in writing, Licensor provides the Work (and each
* Contributor provides its Contributions) on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied, including, without limitation, any warranties or conditions
* of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
* PARTICULAR PURPOSE. You are solely responsible for determining the
* appropriateness of using or redistributing the Work and assume any
* risks associated with Your exercise of permissions under this License.
*
* 8. Limitation of Liability. In no event and under no legal theory,
* whether in tort (including negligence), contract, or otherwise,
* unless required by applicable law (such as deliberate and grossly
* negligent acts) or agreed to in writing, shall any Contributor be
* liable to You for damages, including any direct, indirect, special,
* incidental, or consequential damages of any character arising as a
* result of this License or out of the use or inability to use the
* Work (including but not limited to damages for loss of goodwill,
* work stoppage, computer failure or malfunction, or any and all
* other commercial damages or losses), even if such Contributor
* has been advised of the possibility of such damages.
*
* 9. Accepting Warranty or Additional Liability. While redistributing
* the Work or Derivative Works thereof, You may choose to offer,
* and charge a fee for, acceptance of support, warranty, indemnity,
* or other liability obligations and/or rights consistent with this
* License. However, in accepting such obligations, You may act only
* on Your own behalf and on Your sole responsibility, not on behalf
* of any other Contributor, and only if You agree to indemnify,
* defend, and hold each Contributor harmless for any liability
* incurred by, or claims asserted against, such Contributor by reason
* of your accepting any such warranty or additional liability.
*
* END OF TERMS AND CONDITIONS
*
* APPENDIX: How to apply the Apache License to your work.
*
* To apply the Apache License to your work, attach the following
* boilerplate notice, with the fields enclosed by brackets "[]"
* replaced with your own identifying information. (Don't include
* the brackets!) The text should be enclosed in the appropriate
* comment syntax for the file format. We also recommend that a
* file or class name and description of purpose be included on the
* same "printed page" as the copyright notice for easier
* identification within third-party archives.
*
* Copyright [yyyy] [name of copyright owner]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

View file

@ -0,0 +1,30 @@
/*
* Copyright (c) 1996-2004, Jon Meyer
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions
* and the following disclaimer in the documentation and/or other materials provided with the
* distribution.
*
* Neither the name of the Jon Meyer nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Jasmin was written by Jon Meyer, www.cybergrain.com
* The Jasmin website is jasmin.sourceforge.net.
*/

138
jasmin/jasmin-2.4/makefile Normal file
View file

@ -0,0 +1,138 @@
JDK = E:/JDK/BIN/
SRC = src/Jasmin.java \
src/jasmin/ClassFile.java \
src/jasmin/InsnInfo.java \
src/jasmin/Main.java \
src/jasmin/num_token.java \
src/jasmin/parser.java \
src/jasmin/relative_num_token.java \
src/jasmin/ReservedWords.java \
src/jasmin/Scanner.java \
src/jasmin/ScannerUtils.java \
src/jasmin/sym.java \
src/jasmin/var_token.java \
src/jas/Annotation.java \
src/jas/AnnotationAttr.java \
src/jas/AnnotationElement.java \
src/jas/AnnotDefAttr.java \
src/jas/AnnotParamAttr.java \
src/jas/AsciiCP.java \
src/jas/CatchEntry.java \
src/jas/Catchtable.java \
src/jas/ClassCP.java \
src/jas/ClassEnv.java \
src/jas/CodeAttr.java \
src/jas/ConstAttr.java \
src/jas/CP.java \
src/jas/DeprecatedAttr.java \
src/jas/DoubleCP.java \
src/jas/EnclosingMethodAttr.java \
src/jas/ExceptAttr.java \
src/jas/FieldCP.java \
src/jas/FloatCP.java \
src/jas/GenericAttr.java \
src/jas/IincInsn.java \
src/jas/InnerClass.java \
src/jas/InnerClassesAttr.java \
src/jas/Insn.java \
src/jas/InsnOperand.java \
src/jas/IntegerCP.java \
src/jas/InterfaceCP.java \
src/jas/InvokeinterfaceInsn.java \
src/jas/jasError.java \
src/jas/Label.java \
src/jas/LabelOrOffset.java \
src/jas/LineTableAttr.java \
src/jas/LocalVarEntry.java \
src/jas/LocalVarTableAttr.java \
src/jas/LocalVarTypeTableAttr.java \
src/jas/LongCP.java \
src/jas/LookupswitchInsn.java \
src/jas/Method.java \
src/jas/MethodCP.java \
src/jas/MultiarrayInsn.java \
src/jas/NameTypeCP.java \
src/jas/RuntimeConstants.java \
src/jas/SignatureAttr.java \
src/jas/SourceAttr.java \
src/jas/SourceDebugExtensionAttr.java \
src/jas/StackMap.java \
src/jas/StringCP.java \
src/jas/TableswitchInsn.java \
src/jas/Var.java \
src/jas/VerificationTypeInfo.java \
src/jas/VerifyFrame.java \
src/java_cup/runtime/char_token.java \
src/java_cup/runtime/double_token.java \
src/java_cup/runtime/float_token.java \
src/java_cup/runtime/int_token.java \
src/java_cup/runtime/long_token.java \
src/java_cup/runtime/lr_parser.java \
src/java_cup/runtime/str_token.java \
src/java_cup/runtime/symbol.java \
src/java_cup/runtime/token.java \
src/java_cup/runtime/virtual_parse_stack.java \
src/jasmin.mf
CUP = src/java_cup/Main.java \
src/java_cup/action_part.java \
src/java_cup/action_production.java \
src/java_cup/emit.java \
src/java_cup/internal_error.java \
src/java_cup/lalr_item.java \
src/java_cup/lalr_item_set.java \
src/java_cup/lalr_state.java \
src/java_cup/lalr_transition.java \
src/java_cup/lexer.java \
src/java_cup/lr_item_core.java \
src/java_cup/non_terminal.java \
src/java_cup/parse_action.java \
src/java_cup/parse_action_row.java \
src/java_cup/parse_action_table.java \
src/java_cup/parse_reduce_row.java \
src/java_cup/parse_reduce_table.java \
src/java_cup/parser.cup \
src/java_cup/parser.java \
src/java_cup/production.java \
src/java_cup/production_part.java \
src/java_cup/reduce_action.java \
src/java_cup/shift_action.java \
src/java_cup/sym.java \
src/java_cup/symbol.java \
src/java_cup/symbol_part.java \
src/java_cup/symbol_set.java \
src/java_cup/terminal.java \
src/java_cup/terminal_set.java \
src/java_cup/version.java \
src/java_cup/runtime/lr_parser.java \
src/java_cup/runtime/str_token.java \
src/java_cup/runtime/symbol.java \
src/java_cup/runtime/token.java \
src/java_cup/runtime/virtual_parse_stack.java \
src/java_cup.mf
##########################################################################
jasmin.jar : $(SRC)
@if not exist out\nul mkdir out
@$(JDK)javac -extdirs "" -source 1.2 -target 1.1 -d out -cp src src/Jasmin.java
@$(JDK)jar cfm jasmin.jar src/jasmin.mf -C out .
src/jasmin/parser.java:
src/jasmin/sym.java: src/jasmin/parser.cup java_cup.jar
@$(JDK)java -jar java_cup.jar -out src/jasmin -nosummary <src/jasmin/parser.cup
######################
java_cup.jar : $(CUP)
@if not exist out_cup\nul mkdir out_cup
@if exist java_cup.jar copy java_cup.jar out_cup >nul
@$(JDK)javac -extdirs "" -source 1.2 -target 1.1 -d out_cup -cp src src/java_cup/Main.java
@$(JDK)jar cfm java_cup.jar src/java_cup.mf -C out_cup .
src/java_cup/parser.java:
src/java_cup/sym.java: src/java_cup/parser.cup
@$(JDK)java -jar java_cup.jar -out src/java_cup -nosummary <src/java_cup/parser.cup
#########EOF######

View file

@ -0,0 +1,6 @@
import jasmin.Main;
public class Jasmin {
public static void main(String args[])
{ Main.main(args); }
}

View file

@ -0,0 +1,38 @@
/**
* This attribute can associated with a method, field or class.
*
* @author $Author: Iouri Kharon $
* @version $Revision: 1.0 $
*/
package jas;
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
public class AnnotDefAttr
{
static final CP attr = new AsciiCP("AnnotationDefault");
Annotation ann;
public AnnotDefAttr()
{ ann = new Annotation(); }
public Annotation get()
{ return(ann); }
void resolve(ClassEnv e)
{
e.addCPItem(attr);
ann.resolve(e);
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr));
out.writeInt(ann.size());
ann.write(e, out);
}
}

View file

@ -0,0 +1,72 @@
/**
* This attribute can associated with a method, field or class.
*
* @author $Author: Iouri Kharon $
* @version $Revision: 1.0 $
*/
package jas;
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
public class AnnotParamAttr
{
CP attr;
Vector anns; // Vector<Vector<Annotation>>
public AnnotParamAttr(boolean visible)
{
attr = new AsciiCP(visible ? "RuntimeVisibleParameterAnnotations" :
"RuntimeInvisibleParameterAnnotations");
anns = new Vector();
}
public void add(Annotation annotation, int paramnum)
{
Vector ap = null;
int top = anns.size();
if(paramnum < top) ap = (Vector)anns.elementAt(paramnum);
if(ap == null) {
if(paramnum >= top) anns.setSize(paramnum+1);
anns.set(paramnum, ap = new Vector());
}
ap.add(annotation);
}
void resolve(ClassEnv e)
{
e.addCPItem(attr);
for(int i = 0, top = anns.size(); i < top; i++) {
Vector ap = (Vector)anns.elementAt(i);
if(ap == null) continue;
for(Enumeration en = ap.elements(); en.hasMoreElements(); )
((Annotation)en.nextElement()).resolve(e);
}
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr));
int top = anns.size(), len = 1 + 2*top;
for(int i = 0; i < top; i++) {
Vector ap = (Vector)anns.elementAt(i);
if(ap != null)
for(Enumeration en = ap.elements(); en.hasMoreElements(); )
len += ((Annotation)en.nextElement()).size();
}
out.writeInt(len);
out.writeByte((byte)top);
for(int i = 0; i < top; i++) {
Vector ap = (Vector)anns.elementAt(i);
if(ap == null) out.writeShort(0);
else {
out.writeShort((short)ap.size());
for(Enumeration en = ap.elements(); en.hasMoreElements(); )
((Annotation)en.nextElement()).write(e, out);
}
}
}
}

View file

@ -0,0 +1,113 @@
/**
* @author $Author: Iouri Kharon $
* @version $Revision: 1.0 $
*/
package jas;
// one class to ring them all...
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
/*
void addAnnotation() // default
void addAnnotation(boolean visible, String clname)
void addAnnotation(boolean visible, String clname, int paramnum)
*/
public class Annotation extends CP
{
private Vector fields;
private AsciiCP type;
private Annotation parent;
private AnnotationElement field;
private boolean is_default;
public static final void ParserError() throws jasError
{ throw new jasError("internal logic error in annotation parsing"); }
private Annotation(Annotation parent, AsciiCP type)
{
this.type = type;
this.parent = parent;
field = null;
fields = new Vector();
}
public Annotation(String type)
{ this(null, new AsciiCP(type)); }
public Annotation() // fictive for AnnotationDefault
{ this(null, null); }
public Annotation nestAnnotation() throws jasError
{
if(field == null) ParserError();
Annotation tmp = new Annotation(this, field.nestType());
field.addValue(tmp);
return(tmp);
}
public Annotation endAnnotation() throws jasError
{
if(field != null) {
field.done();
field = null;
}
return(parent);
}
public void addField(String name, String type, String add)
throws jasError
{
if(this.type == null && fields.size() != 0) ParserError();
if(field != null) {
field.done();
field = null;
}
if((name == null) != (this.type == null)) ParserError();
field = new AnnotationElement(name, type, add);
fields.add(field);
}
public void addValue(Object value) throws jasError
{
if(field == null) ParserError();
field.addValue(value);
}
void resolve(ClassEnv e)
{
if(type != null) e.addCPItem(type);
for(Enumeration en = fields.elements(); en.hasMoreElements(); )
((AnnotationElement)en.nextElement()).resolve(e);
}
int size() throws jasError
{
if(field != null) ParserError();
int len = 2 + 2;
if(type == null) {
if(fields.size() != 1) ParserError();
len = 0;
}
for(Enumeration en = fields.elements(); en.hasMoreElements(); )
len += ((AnnotationElement)en.nextElement()).size();
return(len);
}
void write(ClassEnv e, DataOutputStream out) throws IOException, jasError
{
if(field != null) ParserError();
if(type != null) {
out.writeShort(e.getCPIndex(type));
out.writeShort((short)fields.size());
} else if(fields.size() != 1) ParserError();
for(Enumeration en = fields.elements(); en.hasMoreElements(); )
((AnnotationElement)en.nextElement()).write(e, out);
}
}

View file

@ -0,0 +1,48 @@
/**
* This attribute can associated with a method, field or class.
*
* @author $Author: Iouri Kharon $
* @version $Revision: 1.0 $
*/
package jas;
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
public class AnnotationAttr
{
CP attr;
Vector anns;
public AnnotationAttr(boolean visible)
{
attr = new AsciiCP(visible ? "RuntimeVisibleAnnotations" :
"RuntimeInvisibleAnnotations");
anns = new Vector();
}
public void add(Annotation annotation)
{ anns.add(annotation); }
void resolve(ClassEnv e)
{
e.addCPItem(attr);
for(Enumeration en = anns.elements(); en.hasMoreElements(); )
((Annotation)en.nextElement()).resolve(e);
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr));
int len = 2;
for(Enumeration en = anns.elements(); en.hasMoreElements(); )
len += ((Annotation)en.nextElement()).size();
out.writeInt(len);
out.writeShort((short)anns.size());
for(Enumeration en = anns.elements(); en.hasMoreElements(); )
((Annotation)en.nextElement()).write(e, out);
}
}

View file

@ -0,0 +1,234 @@
/**
* AnnotationElement are used by Annotation attributes
* @author $Author: Iouri Kharon $
* @version $Revision: 1.0 $
*/
package jas;
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
public class AnnotationElement
{
private boolean array;
private char sign;
private CP name, exttype;
private Vector values;
private static final char type_int = 'I'; // integer
private static final char type_byte = 'B'; // signed byte
private static final char type_char = 'C'; // unicode character
private static final char type_short = 'S'; // signed short
private static final char type_bool = 'Z'; // boolean true or false
// end of int types
private static final char type_float = 'F'; // single precision IEEE foat
private static final char type_double = 'D'; // double precision IEEE float
private static final char type_long = 'J'; // long integer
//prefix
private static final char type_array = '[';
//annotation special
private static final char type_string = 's'; // constant string
private static final char type_class = 'c'; // return type descriptor
//complex types
private static final char type_enum = 'e'; // enum constant (type + name)
private static final char type_annot = '@'; // nested annotation
private static void badsignature() throws jasError
{ throw new jasError("invalid type signature for annotation field"); }
public AnnotationElement(String name, String type, String exttype)
throws jasError
{
this.name = null;
if(name != null) this.name = new AsciiCP(name);
values = new Vector();
array = false;
sign = type.charAt(0);
if(sign != type_array) {
if(type.length() != 1) badsignature();
} else {
array = true;
if(type.length() != 2) badsignature();
sign = type.charAt(1);
}
switch(sign) {
default:
badsignature();
case type_enum:
case type_annot:
if(exttype == null) badsignature();
this.exttype = new AsciiCP(exttype);
break;
case type_int:
case type_byte:
case type_char:
case type_short:
case type_bool:
case type_float:
case type_double:
case type_long:
case type_string:
case type_class:
if(exttype != null) badsignature();
this.exttype = null;
break;
}
}
void addValue(Object value) throws jasError
{
if(value == null) Annotation.ParserError();
if(!array && values.size() != 0)
throw new jasError("too many values for nonarray annotation field type");
CP cp = null;
switch(sign) {
case type_char:
case type_bool:
case type_byte:
case type_short:
case type_int:
if(value instanceof Integer) {
int val = ((Integer)value).intValue();
boolean badval = false;
switch(sign) {
case type_bool:
if(val < 0 || val > 1) badval = true;
break;
case type_char:
if(val < 0 || val > 0xFFFF) badval = true;
break;
case type_byte:
if(val < -128 || val > 127) badval = true;
case type_short:
if(val < -32768 || val > 32767) badval = true;
default: // type_int
break;
}
if(badval)
throw new jasError("annotation field value exceed range of type", true);
cp = new IntegerCP(val);
}
break;
case type_float:
if(value instanceof Float)
cp = new FloatCP(((Float)value).floatValue());
break;
case type_double:
if(value instanceof Double) {
cp = new DoubleCP(((Double)value).doubleValue());
} else if(value instanceof Float) {
cp = new DoubleCP(((Float)value).floatValue());
}
break;
case type_long:
if(value instanceof Long) {
cp = new LongCP(((Long)value).longValue());
} else if(value instanceof Integer) {
cp = new LongCP(((Integer)value).intValue());
}
break;
case type_string:
case type_class:
case type_enum:
if(value instanceof String)
cp = new AsciiCP((String)value);
break;
case type_annot:
if(value instanceof Annotation)
cp = (Annotation)value;
default:
break;
}
if(cp == null)
throw new jasError("incompatible value for annotation field type");
values.add(cp);
}
public AsciiCP nestType() throws jasError
{
if(sign != type_annot) Annotation.ParserError();
return((AsciiCP)exttype);
}
public void done() throws jasError
{
switch(values.size()) {
case 1:
return;
default:
if(array) return;
//pass thru
case 0:
Annotation.ParserError();
}
}
void resolve(ClassEnv e)
{
if(name != null) e.addCPItem(name);
if(sign == type_enum) e.addCPItem(exttype);
for(Enumeration en = values.elements(); en.hasMoreElements(); ) {
CP cp = ((CP)en.nextElement());
if(sign != type_annot) e.addCPItem(cp);
else cp.resolve(e);
}
}
int size() throws jasError
{
done();
int len;
if(sign == type_annot) {
len = values.size(); // tags
for(Enumeration en = values.elements(); en.hasMoreElements(); )
len += ((Annotation)en.nextElement()).size();
} else {
len = 1+2;
if(sign == type_enum) len += 2;
len *= values.size();
}
if(array) len += 1+2;
if(name != null) len += 2;
return(len);
}
void write(ClassEnv e, DataOutputStream out) throws IOException, jasError
{
done();
if(name != null) out.writeShort(e.getCPIndex(name));
if(array) {
out.writeByte(type_array);
out.writeShort((short)values.size());
}
short id = 0;
if(sign == type_enum) id = e.getCPIndex(exttype);
for(Enumeration en = values.elements(); en.hasMoreElements(); ) {
out.writeByte(sign);
CP cp = ((CP)en.nextElement());
switch(sign) {
case type_annot:
((Annotation)cp).write(e, out);
break;
case type_enum:
out.writeShort(id);
//pass thru
default:
out.writeShort(e.getCPIndex(cp));
break;
}
}
}
}

View file

@ -0,0 +1,30 @@
/**
* This is a class to create Ascii CP entries.
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class AsciiCP extends CP implements RuntimeConstants
{
/**
* @param s Name of the ascii constant pool entry
*/
public AsciiCP(String s)
{ uniq = s.intern(); }
void resolve(ClassEnv e)
{ return; }
public String toString() { return "AsciiCP: " + uniq; }
void write(ClassEnv e, DataOutputStream out)
throws IOException
{
out.writeByte(CONSTANT_UTF8);
out.writeUTF(uniq);
}
}

View file

@ -0,0 +1,37 @@
/**
* this is an abstraction to contain all the CPE items
* that can be created.
*
* @see AsciiCP
* @see ClassCP
* @see NameTypeCP
* @see FieldCP
* @see InterfaceCP
* @see MethodCP
* @see IntegerCP
* @see LongCP
* @see FloatCP
* @see DoubleCP
* @see StringCP
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
// one class to ring them all...
import java.io.*;
public abstract class CP
{
String uniq;
String getUniq() { return uniq; }
abstract void resolve(ClassEnv e);
abstract void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError;
}

View file

@ -0,0 +1,80 @@
/**
* This class
* is used to build up entries in a catch table.
* @see Catchtable
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class CatchEntry
{
Label start_pc, end_pc, handler_pc;
int start_off, end_off, handler_off;
CP catch_cpe;
/**
* Catch entries are created and then added to the Catchtable.
* @param start Label marking the beginning of the area
* where the catch table is active.
* @param end Label marking the end of the area where the
* table is active.
* @param handler Label marking the entrypoint into the
* exception handling routine.
* @param cat (usually a classCP) informing the VM to direct
* any exceptions of this (or its subclasses) to the handler.
* @see Catchtable
*/
public
CatchEntry(Label start, Label end, Label handler, CP cat)
{
start_pc = start;
end_pc = end;
handler_pc = handler;
catch_cpe = cat;
}
/**
* Catch entries are created and then added to the Catchtable.
* @param start offset marking the beginning of the area
* where the catch table is active.
* @param end offset marking the end of the area where the
* table is active.
* @param handler offset marking the entrypoint into the
* exception handling routine.
* @param cat (usually a classCP) informing the VM to direct
* any exceptions of this (or its subclasses) to the handler.
* @see Catchtable
*/
public
CatchEntry(int start, int end, int handler, CP cat)
{
start_off = start;
end_off = end;
handler_off = handler;
catch_cpe = cat;
}
void resolve(ClassEnv e)
{ if (catch_cpe != null) e.addCPItem(catch_cpe); }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
if(start_pc!=null && end_pc != null && handler_pc != null) {
start_pc.writeOffset(ce, null, out);
end_pc.writeOffset(ce, null, out);
handler_pc.writeOffset(ce, null, out);
} else {
out.writeShort(start_off);
out.writeShort(end_off);
out.writeShort(handler_off);
}
if (catch_cpe != null)
{ out.writeShort(e.getCPIndex(catch_cpe)); }
else
{ out.writeShort(0); }
}
}

View file

@ -0,0 +1,65 @@
/**
* This is used to make a table of catch handlers for a method.
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
import java.util.*;
public class Catchtable
{
Vector entries;
public Catchtable() { entries = new Vector(); }
/**
* add an entry to the catch table
*/
public void addEntry(CatchEntry entry) { entries.addElement(entry); }
/**
* add an entry to the catch table
* @param start Label marking the beginning of the area
* where the catch table is active.
* @param end Label marking the end of the area where the
* table is active.
* @param handler Label marking the entrypoint into the
* exception handling routine.
* @param cat (usually a classCP) informing the VM to direct
* any exceptions of this (or its subclasses) to the handler.
*/
public void
addEntry(Label start, Label end, Label handler, CP cat)
{ addEntry(new CatchEntry(start, end, handler, cat)); }
public void
addEntry(int start, int end, int handler, CP cat)
{ addEntry(new CatchEntry(start, end, handler, cat)); }
void resolve(ClassEnv e)
{
for (Enumeration en=entries.elements(); en.hasMoreElements(); )
{
CatchEntry ce = (CatchEntry)(en.nextElement());
ce.resolve(e);
}
}
int size()
{ return (8*entries.size()); } // each entry is 8 bytes
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(entries.size());
for (Enumeration en = entries.elements(); en.hasMoreElements();)
{
CatchEntry entry = (CatchEntry)(en.nextElement());
entry.write(e, ce, out);
}
}
}

View file

@ -0,0 +1,35 @@
/**
* This is used to create a Class constant pool item
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class ClassCP extends CP implements RuntimeConstants
{
AsciiCP name;
/**
* @param name Name of the class
*/
public ClassCP(String name)
{
uniq = ("CLASS: #$%^#$" + name).intern();
this.name = new AsciiCP(name);
}
void resolve(ClassEnv e)
{ e.addCPItem(name); }
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeByte(CONSTANT_CLASS);
out.writeShort(e.getCPIndex(name));
}
}

View file

@ -0,0 +1,371 @@
package jas;
import java.io.*;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.Vector;
/**
* This is the place where all information about the class to
* be created resides.
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
public class ClassEnv implements RuntimeConstants
{
int magic;
short version_lo, version_hi;
CP this_class, super_class;
short class_access;
Hashtable cpe, cpe_index;
Vector interfaces;
Vector vars;
Vector methods;
SourceAttr source;
SignatureAttr signature;
SourceDebugExtensionAttr debug;
EnclosingMethodAttr enclosing;
DeprecatedAttr depr;
InnerClassesAttr innerclasses;
AnnotationAttr annVis, annInvis;
Vector generic;
public ClassEnv()
{
// Fill in reasonable defaults
magic = JAVA_MAGIC;
version_lo = (short) JAVA_MINOR_VERSION;
version_hi = (short) JAVA_VERSION;
// Initialize bags
cpe = new Hashtable();
cpe_index = null;
interfaces = new Vector();
vars = new Vector();
methods = new Vector();
annVis = annInvis = null;
generic = new Vector();
}
/**
* Define this class to have this name.
* @param name CPE representing name for class. (This is usually
* a ClassCP)
*/
public void setClass(CP name)
{ this_class = name; addCPItem(name); }
/**
* Define this class to have this superclass
* @param name CPE representing name for class. (This is usually
* a ClassCP)
*/
public void setSuperClass(CP name)
{ super_class = name; addCPItem(name); }
/**
* Set the class access for this class. Constants understood
* by this are present along with the java Beta distribution.
* @param access number representing access permissions for
* the entire class.
* @see RuntimeConstants
*/
public void setClassAccess(short access)
{ class_access = access; }
/**
* Add this CP to the list of interfaces supposedly implemented by
* this class. Note that the CP ought to be a ClassCP to make
* sense to the VM.
*/
public void addInterface(CP ifc)
{
addCPItem(ifc);
interfaces.addElement(ifc);
}
/**
* Add this to the list of interfaces supposedly implemented
* by this class. Note that each CP is usually a ClassCP.
* @param ilist An array of CP items representing the
* interfaces implemented by this class.
*/
public void addInterface(CP ilist[])
{
for (int i=0; i<ilist.length; i++)
{
interfaces.addElement(ilist[i]);
addCPItem(ilist[i]);
}
}
public void addField(Var v)
{
vars.addElement(v);
v.resolve(this);
}
/**
* Write the contents of the class.
*
* @param out DataOutputStream on which the contents are written.
*/
public void write(DataOutputStream out)
throws IOException, jasError
{
// Headers
out.writeInt(magic);
out.writeShort(version_lo);
out.writeShort(version_hi);
// cpe items
int curidx = 1;
// make up indices for entries
cpe_index = new Hashtable();
for (Enumeration e = cpe.elements(); e.hasMoreElements();)
{
CP tmp = (CP)(e.nextElement());
cpe_index.put(tmp.getUniq(), new Integer(curidx));
curidx++;
if ((tmp instanceof LongCP) ||
(tmp instanceof DoubleCP))
curidx++;
}
out.writeShort((short)curidx);
// Now write out all the entries
for (Enumeration e = cpe.elements(); e.hasMoreElements();)
{
CP now = (CP) (e.nextElement());
now.write(this, out);
}
// Class hierarchy/access
out.writeShort(class_access);
out.writeShort(getCPIndex(this_class));
out.writeShort(getCPIndex(super_class));
// interfaces
out.writeShort(interfaces.size());
for (Enumeration e = interfaces.elements(); e.hasMoreElements();)
{
CP c = (CP)(e.nextElement());
out.writeShort(getCPIndex(c));
}
// variables
out.writeShort(vars.size());
for (Enumeration e = vars.elements(); e.hasMoreElements();)
{
Var v = (Var)(e.nextElement());
v.write(this, out);
}
// methods
out.writeShort(methods.size());
for (Enumeration e = methods.elements(); e.hasMoreElements();)
{
Method m = (Method)(e.nextElement());
m.write(this, out);
}
// additional attributes
short numExtra = 0;
if (source != null)
{ numExtra++; }
if (debug != null)
{ numExtra++; }
if (enclosing != null)
{ numExtra++; }
if (signature != null)
{ numExtra++; }
if (innerclasses != null)
{ numExtra++; }
if (depr != null)
{ numExtra++; }
if (annVis != null)
{ numExtra++; }
if (annInvis != null)
{ numExtra++; }
numExtra += generic.size();
out.writeShort(numExtra);
if (source != null)
{ source.write(this, out); }
if (debug != null)
{ debug.write(this, out); }
if (enclosing != null)
{ enclosing.write(this, out); }
if (signature != null)
{ signature.write(this, out); }
if (innerclasses != null)
{ innerclasses.write(this, out); }
if (depr != null)
{ depr.write(this, out); }
if (annVis != null)
{ annVis.write(this, out); }
if (annInvis != null)
{ annInvis.write(this, out); }
for (Enumeration gen=generic.elements(); gen.hasMoreElements(); )
{
GenericAttr gattr = (GenericAttr)gen.nextElement();
gattr.write(this, out);
}
out.flush();
}
/**
* This is the method to add CPE items to a class. CPE items for
* a class are "uniquefied". Ie, if you add a CPE items whose
* contents already exist in the class, only one entry is finally
* written out when the class is written.
*
* @param cp Item to be added to the class
*/
public void addCPItem(CP cp)
{
String uniq = cp.getUniq();
CP intern;
if ((intern = (CP)(cpe.get(uniq))) == null)
{
// add it
cpe.put(uniq, cp);
// resolve it so it adds anything
// which it depends on
cp.resolve(this);
}
}
/**
* Add an attribute specifying the name of the source file
* for the class
* @param source SourceAttribute specifying the source for the file
*/
public void setSource(SourceAttr source)
{ this.source = source; source.resolve(this); }
/**
* Add an attribute specifying the name of the source file
* for the clas.
* @param source String with the name of the class
*/
public void setSource(String source)
{ this.source = new SourceAttr(source); this.source.resolve(this); }
/**
* Add an attribute specifying extended debug information
* @param debug String the extended debug information
*/
public void setSourceDebugExtension(String debug)
{
if ( this.debug != null )
this.debug.append(debug);
else {
this.debug = new SourceDebugExtensionAttr(debug);
this.debug.resolve(this);
}
}
/**
* Add an attribute specifying the enclosing method of this class
* @param cls String the enclosing class
* @param mtd String the enclosing method
* @param dsc String the enclosing method descriptor
*/
public void setEnclosingMethod(String cls, String mtd, String dsc)
{ this.enclosing = new EnclosingMethodAttr(cls, mtd, dsc);
this.enclosing.resolve(this); }
/**
* Add an attribute specifying the signature of this class
* @param sig String the signature
*/
public void setSignature(String sig)
{ this.signature = new SignatureAttr(sig);
this.signature.resolve(this); }
public void setDeprecated(DeprecatedAttr depr)
{ this.depr = depr; depr.resolve(this); }
/**
* Add a generic attribute to the class file. A generic attribute
* contains a stream of uninterpreted bytes which is ignored by
* the VM (as long as its name doesn't conflict with other names
* for attributes that are understood by the VM)
*/
public void addGenericAttr(GenericAttr g)
{ generic.addElement(g); g.resolve(this); }
public void addInnerClass(short iacc, String name, String inner, String outer)
{
if(innerclasses == null) {
innerclasses = new InnerClassesAttr();
innerclasses.resolve(this);
}
InnerClass ic = new InnerClass(iacc, name, inner, outer);
ic.resolve(this);
innerclasses.addInnerClass(ic);
}
/*
* procedure group for annotation description
*/
public Annotation addAnnotation(boolean visible, String clsname)
{
Annotation ann = new Annotation(clsname);
AnnotationAttr aa = visible ? annVis : annInvis;
if(aa == null) {
aa = new AnnotationAttr(visible);
if(visible) annVis = aa;
else annInvis = aa;
}
aa.add(ann);
return(ann);
}
public void endHeader()
{
if(annVis != null) annVis.resolve(this);
if(annInvis != null) annInvis.resolve(this);
}
/**
* This allows more control over generating CP's for methods
* if you feel so inclined.
*/
public void addMethod(Method m)
{
m.resolve(this);
methods.addElement(m);
}
short getCPIndex(CP cp)
throws jasError
{
if (cpe_index == null)
throw new jasError("Internal error: CPE index has not been generated");
Integer idx = (Integer)(cpe_index.get(cp.getUniq()));
if (idx == null)
throw new jasError("Item " + cp + " not in the class");
return ((short)(idx.intValue()));
}
/**
* Change the bytecode version of this class
* The version will be version_high.version_low
* @param version_high short
* @param version_low short
*/
public void setVersion(short version_high, short version_low)
{
version_hi = version_high;
version_lo = version_low;
}
}

View file

@ -0,0 +1,218 @@
/**
* CodeAttr's are used as a bag to hold lists of instructions
* until it is time to put them into a Class.
* @see ClassEnv#addMethod
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
import java.util.*;
public class CodeAttr
{
static final CP attr = new AsciiCP("Code");
short stack_size, num_locals;
int code_size;
Vector insns;
Hashtable insn_pc;
Catchtable ctb;
LineTableAttr ltab;
LocalVarTableAttr lvar;
LocalVarTypeTableAttr lvtyp;
StackMap stackmap;
Vector generic;
/**
* Create a new bag. Add instructions with the addInsn() method,
* set the catch table with the setCatchTable() method.
* @see Insn
* @see Catchtable
* @see ClassEnv#addMethod
*/
public CodeAttr()
{
this.stack_size = 1;
this.num_locals = 1;
this.ctb = null;
this.insns = new Vector();
generic = new Vector();
}
/**
* Set the catchtable for this code
*/
public void setCatchtable(Catchtable ctb)
{ this.ctb = ctb; }
/**
* Set the line number table for this method
*/
public void setLineTable(LineTableAttr ltab)
{ this.ltab = ltab; }
/**
* Set the local variable information for this method
*/
public void setLocalVarTable(LocalVarTableAttr lvar)
{ this.lvar = lvar; }
/**
* Set the local variable type information for this method
*/
public void setLocalVarTypeTable(LocalVarTypeTableAttr lvtyp)
{ this.lvtyp = lvtyp; }
/**
* Set the StackMap attribute for this method
*/
public void setStackMap(StackMap s)
{ stackmap = s; }
/**
* Add a generic attribute to the method. A generic attribute
* contains a stream of uninterpreted bytes which is ignored by
* the VM (as long as its name doesn't conflict with other names
* for attributes that are understood by the VM)
*/
public void addGenericAttr(GenericAttr g)
{ generic.addElement(g); }
/**
* Append a new Insn to this code. Insn's are sequentially
* stored, in the order in which this method is called. You
* can't reorder code fragments after you've added it here.
*/
public void addInsn(Insn insn)
{ insns.addElement(insn); }
public void setStackSize(short stack_size)
{ this.stack_size = stack_size; }
public void setVarSize(short num_vars)
{ num_locals = num_vars; }
void resolve(ClassEnv e)
{
// propagate this resolution to
// the insns and catch table, so
// that any CP's referenced by them
// also get added.
e.addCPItem(attr);
for (Enumeration en = insns.elements(); en.hasMoreElements();)
{
Insn i = (Insn)(en.nextElement());
i.resolve(e);
}
if (ctb != null) ctb.resolve(e);
if (ltab != null) ltab.resolve(e);
if (lvar != null) lvar.resolve(e);
if (lvtyp != null) lvtyp.resolve(e);
if (stackmap != null) stackmap.resolve(e);
for (Enumeration gen = generic.elements(); gen.hasMoreElements();)
{
GenericAttr gattr = (GenericAttr)gen.nextElement();
gattr.resolve(e);
}
}
int getPc(Insn i) throws jasError
{
if (insn_pc == null)
throw new jasError("Internal error, insn_pc has not been initialized");
Integer tmp;
if (i instanceof Label)
{
tmp = (Integer)(insn_pc.get(((Label)i).id));
}
else
{
tmp = (Integer)(insn_pc.get(i));
}
if (tmp == null)
throw new jasError(i + " has not been added to the code");
return tmp.intValue();
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
// First, resolve all labels and
// compute total size
int code_size = 0;
insn_pc = new Hashtable();
for (Enumeration en = insns.elements(); en.hasMoreElements();)
{
Insn now = (Insn)(en.nextElement());
if (now instanceof Label)
{
insn_pc.put(((Label)now).id, new Integer(code_size));
}
else
{ insn_pc.put(now, new Integer(code_size)); }
code_size += now.size(e, this);
}
int total_size = code_size;
if (ctb != null) total_size += ctb.size();
if (ltab != null) total_size += ltab.size();
if (lvar != null) total_size += lvar.size();
if (lvtyp != null) total_size += lvtyp.size();
if (stackmap != null) total_size += stackmap.size(e, this);
for (Enumeration gen = generic.elements(); gen.hasMoreElements();)
{
GenericAttr gattr = (GenericAttr)(gen.nextElement());
total_size += gattr.size();
}
// extra headers
total_size += 12;
out.writeShort(e.getCPIndex(attr));
out.writeInt(total_size);
out.writeShort(stack_size);
out.writeShort(num_locals);
out.writeInt(code_size);
for (Enumeration en = insns.elements(); en.hasMoreElements();)
{
Insn now = (Insn)(en.nextElement());
now.write(e, this, out);
}
if (ctb != null)
{ ctb.write(e, this, out); }
else
{ out.writeShort(0); }
short extra = 0;
if (ltab != null) extra++;
if (lvar != null) extra++;
if (lvtyp != null) extra++;
if (stackmap != null) extra++;
extra += generic.size();
out.writeShort(extra);
if (ltab != null)
{ ltab.write(e, this, out); }
if (lvar != null)
{ lvar.write(e, this, out); }
if (lvtyp != null)
{ lvtyp.write(e, this, out); }
if (stackmap != null)
{ stackmap.write(e, this, out); }
for (Enumeration gen = generic.elements(); gen.hasMoreElements();)
{
GenericAttr gattr = (GenericAttr)gen.nextElement();
gattr.write(e, out);
}
}
public String toString()
{ return ("<#code-attr>"); }
}

View file

@ -0,0 +1,43 @@
/**
* This is typically used to represent a constant value for
* a field entry (as in static final int foo = 20).
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class ConstAttr
{
static final CP attr = new AsciiCP("ConstantValue");
CP val;
/**
* Create a new constant attribute whose constant value
* is picked up from constant pool with the given entry.
* @param val Constant pool item whose value is associated
* with the constant value attribute
*/
public ConstAttr(CP val)
{ this.val = val; }
void resolve(ClassEnv e)
{
e.addCPItem(val);
e.addCPItem(attr);
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr));
out.writeInt(2);
out.writeShort(e.getCPIndex(val));
}
}

View file

@ -0,0 +1,32 @@
/**
* This attribute is used to mark class/method/field as deprecated.
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class DeprecatedAttr
{
static final CP attr = new AsciiCP("Deprecated");
/**
* Create a deprecated attribute.
* @see ClassEnv#setDeprecated
*/
public DeprecatedAttr() { }
void resolve(ClassEnv e)
{ e.addCPItem(attr); }
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr));
out.writeInt(0);
}
}

View file

@ -0,0 +1,32 @@
package jas;
import java.io.*;
/**
* Wrap an Double constant reference with this CPE.
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
public class DoubleCP extends CP implements RuntimeConstants
{
double val;
/**
* @param n Value for Double constant
*/
public DoubleCP(double n)
{
uniq = ("Double: @#$" + n).intern();
val = n;
}
void resolve(ClassEnv e) { return; }
void write(ClassEnv e, DataOutputStream out)
throws IOException
{
out.writeByte(CONSTANT_DOUBLE);
out.writeDouble(val);
}
}

View file

@ -0,0 +1,55 @@
/**
* This attribute is used to define the enclosing method of this class
* @author $Author: Daniel Reynaud $
* @version $Revision: 1.0 $
*/
package jas;
import java.io.*;
public class EnclosingMethodAttr
{
static final CP attr = new AsciiCP("EnclosingMethod");
CP clscp,
ntcp;
String cls, mtd, dsc;
/**
* Create an EnclosingMethod attribute
* @param cls Name of the enclosing class
* @param mtd Name of the enclosing method (can be null)
* @param dsc Name of the enclosing method descriptor (can be null)
* @see ClassEnv#setEnclosingMethod
*/
public EnclosingMethodAttr(String cls, String mtd, String dsc)
{ this.cls = cls;
this.mtd = mtd;
this.dsc = dsc;
clscp = new ClassCP(cls);
if(mtd!=null && dsc!=null)
ntcp = new NameTypeCP(mtd, dsc);
}
void resolve(ClassEnv e)
{ e.addCPItem(attr);
e.addCPItem(clscp); // add the CONSTANT_Class
clscp.resolve(e); // add the CONSTANT_Utf8 for the class name
if(ntcp!=null) {
e.addCPItem(ntcp); // add the CONSTANT_NameAndType
ntcp.resolve(e); // add the two CONSTANT_Utf8
}
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr));
out.writeInt(4);
out.writeShort(e.getCPIndex(clscp));
out.writeShort(ntcp==null ? 0 : e.getCPIndex(ntcp));
}
}

View file

@ -0,0 +1,45 @@
/**
* This attribute is associated with a method, and indicates
* the set of exceptions (as classCP items) that can be thrown
* by the method.
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
import java.util.*;
public class ExceptAttr
{
static final CP attr = new AsciiCP("Exceptions");
Vector cps;
public ExceptAttr() { cps = new Vector(); }
/**
* @param cp Exception class to be added to attribute. This is
* typically a ClassCP
*/
public void addException(CP cp)
{ cps.addElement(cp); }
void resolve(ClassEnv e)
{
e.addCPItem(attr);
for (Enumeration en = cps.elements(); en.hasMoreElements();)
{ e.addCPItem((CP)(en.nextElement())); }
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr));
out.writeInt(cps.size()*2 + 2);
out.writeShort(cps.size());
for (Enumeration en = cps.elements(); en.hasMoreElements();)
{ out.writeShort(e.getCPIndex((CP)(en.nextElement()))); }
}
}

View file

@ -0,0 +1,51 @@
/**
* FieldCP's are used to refer to a field in a particular
* class.
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class FieldCP extends CP implements RuntimeConstants
{
ClassCP clazz;
NameTypeCP nt;
/**
* FieldCP's are created by specifying the class to which the
* field belongs, the name of the symbol, and its signature.
* For instance, to refer to the field <tt>out</tt> in
* <tt>System.out</tt> use
* <tt> new FieldCP("java/lang/System", "out", "Ljava/io/PrintStream;")</tt>
*
* @param clazz Name of class
* @param name Name of symbol
* @param sig Signature for symbol
*/
public FieldCP(String clazz, String name, String sig)
{
uniq = (clazz + "&%$#&" + name + "*()#$" + sig).intern();
this.clazz = new ClassCP(clazz);
this.nt = new NameTypeCP(name, sig);
}
void resolve(ClassEnv e)
{
e.addCPItem(clazz);
e.addCPItem(nt);
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeByte(CONSTANT_FIELD);
out.writeShort(e.getCPIndex(clazz));
out.writeShort(e.getCPIndex(nt));
}
}

View file

@ -0,0 +1,32 @@
package jas;
import java.io.*;
/**
* Wrap an Float constant reference with this CPE.
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
public class FloatCP extends CP implements RuntimeConstants
{
float val;
/**
* @param n Value for Float constant
*/
public FloatCP(float n)
{
uniq = ("Float: @#$" + n).intern();
val = n;
}
void resolve(ClassEnv e) { return; }
void write(ClassEnv e, DataOutputStream out)
throws IOException
{
out.writeByte(CONSTANT_FLOAT);
out.writeFloat(val);
}
}

View file

@ -0,0 +1,75 @@
/**
* This is an opaque attribute that lets you add an uninterpreted
* stream of bytes into an attribute in a class file. This can be
* used (for instance) to embed versioning or signatures into the
* class file or method.
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class GenericAttr
{
CP attr_name;
byte data[];
/**
* Make up a new attribute
* @param data stream of bytes to be placed with the attribute
* @see ClassEnv#addGenericAttr
* @see CodeAttr#addGenericAttr
*/
public GenericAttr(String name, byte data[])
{
attr_name = new AsciiCP(name);
this.data = data;
}
/**
* Make up a new attribute
* @param name CP to be defined as the name of the attribute
* @param data stream of bytes to be placed with the attribute
* @see ClassEnv#addGenericAttr
* @see CodeAttr#addGenericAttr
*/
public GenericAttr(CP name, byte data[])
{
attr_name = name;
this.data = data;
}
/**
* Make up a new attribute
* @param name Name to be associated with the attribute
* @param file name of file with attribute contens
*/
public GenericAttr(String name, String file) throws IOException, jasError
{
FileInputStream inp;
try {
inp = new FileInputStream(file);
} catch(FileNotFoundException e) {
throw new jasError("Generic atribute file " +file+ " not found");
}
data = new byte[inp.available()];
inp.read(data);
inp.close();
attr_name = new AsciiCP(name);
}
void resolve(ClassEnv e)
{ e.addCPItem(attr_name); }
int size()
{ return (2 + 4 + data.length); }
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr_name));
out.writeInt(data.length);
out.write(data);
}
}

View file

@ -0,0 +1,38 @@
/**
* Some instructions are perniticky enough that its simpler
* to write them separately instead of smushing them with
* all the rest. the iinc instruction is one of them.
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class IincInsn extends Insn implements RuntimeConstants
{
/**
* @param vindex Index of variable to be incremented.
* @param increment value to be added to the variable.
*
* A wide prefix is automatically added if either the
* vindex exceeds 256, or the increment value lies
* outside the range [-128, 127]
*
* The VM spec is unclear on how the wide instruction is implemented,
* but the implementation makes <em>both</em> the constant and the
* variable index 16 bit values for the wide version of this instruction.
*/
public IincInsn(int vindex, int increment, boolean Wide)
{
opc = opc_iinc;
operand = new IincOperand(vindex, increment, Wide);
}
}
/* --- Revision History ---------------------------------------------------
--- Iouri Kharon, Aug 10 2006
Added 'Wide' prefix support
*/

View file

@ -0,0 +1,60 @@
/**
* @author $Author: Iouri Kharon $
* @version $Revision: 1.0 $
*/
package jas;
import java.io.*;
public class InnerClass
{
ClassCP inner, outer;
CP name;
short access;
public static int size()
{ return (4 * 2); }
/**
* Make up a new attribute
* @see ClassEnv#addInnerClass
*/
public InnerClass(short access, String name, String inner, String outer)
{
this.access = access;
this.name = null;
if(name != null) this.name = new AsciiCP(name);
this.inner = null;
if(inner != null) this.inner = new ClassCP(inner);
this.outer = null;
if(outer != null) this.outer = new ClassCP(outer);
}
void resolve(ClassEnv e)
{
if(name != null) e.addCPItem(name);
if(inner != null) {
e.addCPItem(inner);
inner.resolve(e);
}
if(outer != null) {
e.addCPItem(outer);
outer.resolve(e);
}
}
void write(ClassEnv e, DataOutputStream out) throws IOException, jasError
{
short id = 0;
if(inner != null) id = e.getCPIndex(inner);
out.writeShort(id);
id = 0;
if(outer != null) id = e.getCPIndex(outer);
out.writeShort(id);
id = 0;
if(name != null) id = e.getCPIndex(name);
out.writeShort(id);
out.writeShort(access);
}
}

View file

@ -0,0 +1,39 @@
/**
* @author $Author: Iouri Kharon $
* @version $Revision: 1.0 $
*/
package jas;
import java.io.*;
import java.util.Vector;
import java.util.Enumeration;
public class InnerClassesAttr
{
static final CP attr = new AsciiCP("InnerClasses");
private Vector list;
public InnerClassesAttr()
{ list = new Vector(); }
public void addInnerClass(InnerClass item)
{ list.add(item); }
void resolve(ClassEnv e)
{
e.addCPItem(attr);
for(Enumeration en = list.elements(); en.hasMoreElements(); )
((InnerClass)en.nextElement()).resolve(e);
}
void write(ClassEnv e, DataOutputStream out) throws IOException, jasError
{
out.writeShort(e.getCPIndex(attr));
out.writeInt((list.size() * InnerClass.size()) + 2);
out.writeShort((short)list.size());
for(Enumeration en = list.elements(); en.hasMoreElements(); )
((InnerClass)en.nextElement()).write(e, out);
}
}

View file

@ -0,0 +1,333 @@
/**
* An Insn is a generic instruction that is added to a
* CodeAttr to build up the code for a method.
* @see CodeAttr
* @see RuntimeConstants
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
import java.util.*;
public class Insn implements RuntimeConstants
{
int opc;
InsnOperand operand;
// private constructor, for the
// "strange" opcodes
Insn() { return; }
/**
* Instructions with no arguments are built with
* this constructor.
*/
public Insn(int opc)
throws jasError
{
if (opcLengths[opc] == 1)
{ operand = null; this.opc = opc; return; }
throw new jasError
(opcNames[opc] + " cannot be used without more parameters");
}
private void check_short(int val, int opc) throws jasError
{
if (val > 32767 || val < -32768)
throw new jasError
(opcNames[opc] + " numeric value exceed size for short");
}
/**
* Instructions that take a single numeric argument. These are
* opc_bipush,
* opc_sipush,
* opc_ret,
* opc_iload,
* opc_lload,
* opc_fload,
* opc_dload,
* opc_aload,
* opc_istore,
* opc_lstore,
* opc_fstore,
* opc_dstore,
* opc_astore,
* opc_newarray
*
* Note that an extra wide prefix is automatically added
* for the following instructions if the numeric argument
* is larger than 256. Also note that while the spec makes
* no mention of opc_ret as being a "wideable" opcode, thats
* how the VM is implemented.
*
* opc_ret:
* opc_iload:
* opc_lload:
* opc_fload:
* opc_dload:
* opc_aload:
* opc_istore:
* opc_lstore:
* opc_fstore:
* opc_dstore:
* opc_astore:
*
*/
/**
* Added branch instructions
*/
public Insn(int opc, int val, boolean Wide)
throws jasError
{
this.opc = opc;
switch (opc)
{
case opc_bipush:
if(val > 127 || val < -128)
throw new jasError("bipush value exceed size of byte", true);
operand = new ByteOperand(val);
break;
case opc_sipush:
case opc_goto:
case opc_if_acmpeq:
case opc_if_acmpne:
case opc_if_icmpeq:
case opc_if_icmpge:
case opc_if_icmpgt:
case opc_if_icmple:
case opc_if_icmplt:
case opc_if_icmpne:
case opc_ifeq:
case opc_ifge:
case opc_ifgt:
case opc_ifle:
case opc_iflt:
case opc_ifne:
case opc_ifnonnull:
case opc_ifnull:
case opc_jsr:
check_short(val, opc);
operand = new OffsetOperand(this, val); break;
case opc_goto_w:
case opc_jsr_w:
operand = new OffsetOperand(this, val, true); break;
case opc_newarray:
if(val < 0 || val > 255)
throw new jasError("newarray counter is illegal", true);
operand = new UnsignedByteOperand(val);
break;
case opc_ret:
case opc_iload:
case opc_lload:
case opc_fload:
case opc_dload:
case opc_aload:
case opc_istore:
case opc_lstore:
case opc_fstore:
case opc_dstore:
case opc_astore:
operand = new UnsignedByteWideOperand(val, Wide);
break;
default:
throw new jasError
(opcNames[opc] + " does not take a numeric argument");
}
}
// used for relative offsets (ex : goto $+5)
public Insn(int opc, int val, char relative)
throws jasError
{
this.opc = opc;
switch (opc)
{
case opc_goto:
case opc_if_acmpeq:
case opc_if_acmpne:
case opc_if_icmpeq:
case opc_if_icmpge:
case opc_if_icmpgt:
case opc_if_icmple:
case opc_if_icmplt:
case opc_if_icmpne:
case opc_ifeq:
case opc_ifge:
case opc_ifgt:
case opc_ifle:
case opc_iflt:
case opc_ifne:
case opc_ifnonnull:
case opc_ifnull:
case opc_jsr:
check_short(val, opc);
operand = new RelativeOffsetOperand(this, val); break;
case opc_goto_w:
case opc_jsr_w:
operand = new RelativeOffsetOperand(this, val, true); break;
default:
throw new jasError
(opcNames[opc] + " does not take a relative numeric argument");
}
}
/**
* Instructions that take a Label as an argument. These are
* opc_jsr,
* opc_goto,
* opc_if_acmpne,
* opc_if_acmpeq,
* opc_if_icmpge,
* opc_if_icmple,
* opc_if_icmpgt,
* opc_if_icmplt,
* opc_if_icmpne,
* opc_if_icmpeq,
* opc_ifge,
* opc_ifgt,
* opc_ifne,
* opc_ifle,
* opc_iflt,
* opc_ifeq,
* opc_ifnull,
* opc_ifnonnull,
* opc_goto_w,
* opc_jsr_w
*/
public Insn(int opc, Label target, int line)
throws jasError
{
this.opc = opc;
switch(opc)
{
case opc_jsr:
case opc_goto:
case opc_if_acmpne:
case opc_if_acmpeq:
case opc_if_icmpge:
case opc_if_icmple:
case opc_if_icmpgt:
case opc_if_icmplt:
case opc_if_icmpne:
case opc_if_icmpeq:
case opc_ifge:
case opc_ifgt:
case opc_ifne:
case opc_ifle:
case opc_iflt:
case opc_ifeq:
case opc_ifnull:
case opc_ifnonnull:
operand = new LabelOperand(target, this, line);
break;
case opc_goto_w:
case opc_jsr_w:
operand = new LabelOperand(target, this, true, line);
break;
default:
throw new jasError
(opcNames[opc] + " does not take a label as its argument");
}
}
/**
* This constructor is used for instructions that take a CP item
* as their argument. These are
* opc_anewarray,
* opc_ldc_w,
* opc_ldc2_w,
* opc_invokedynamic,
* opc_invokenonvirtual,
* opc_invokestatic,
* opc_invokevirtual,
* opc_new,
* opc_checkcast,
* opc_instanceof,
* opc_getstatic,
* opc_putstatic,
* opc_getfield,
* opc_putfield,
* opc_ldc
*/
public Insn(int opc, CP arg)
throws jasError
{
this.opc = opc;
switch(opc)
{
case opc_anewarray:
case opc_invokedynamic:
case opc_invokenonvirtual:
case opc_invokestatic:
case opc_invokevirtual:
case opc_new:
case opc_checkcast:
case opc_instanceof:
case opc_getstatic:
case opc_putstatic:
case opc_getfield:
case opc_putfield:
operand = new CPOperand(arg);
break;
case opc_ldc2_w:
case opc_ldc_w:
operand = new LdcOperand(this, arg);
break;
case opc_ldc:
operand = new LdcOperand(this, arg, false);
break;
default:
throw new jasError
(opcNames[opc] + " does not take a CP item as an argument");
}
}
// This allows the Insn a chance to
// add things to the global env if
// necessary. The CPInsnOperands
// use this to add the CP to the
// classEnv
void resolve(ClassEnv e)
{ if (operand != null) { operand.resolve(e); } }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
if (operand != null)
operand.writePrefix(e, ce, out);
out.writeByte((byte) opc);
if (operand != null)
operand.write(e, ce, out);
}
int size(ClassEnv e, CodeAttr ce)
throws jasError
{
if (operand == null) return 1;
return (1 + operand.size(e, ce));
}
public String toString() {
return "instruction "+opc+" "+((operand!=null)?operand.toString():"");
}
}
/* --- Revision History ---------------------------------------------------
--- Iouri Kharon, Aug 10 2006
Added 'wide' prefix to some instructions
*/

View file

@ -0,0 +1,465 @@
// This is not visible outside the
// package. It is used to
// handle the various types
// of operands used by Insns.
package jas;
import java.io.*;
abstract class InsnOperand
{
abstract void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError;
abstract int size(ClassEnv e, CodeAttr code) throws jasError;
abstract void resolve(ClassEnv e);
void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{ return; }
}
// Used to implement targets of Insns
class LabelOperand extends InsnOperand
{
Label target;
Insn source;
boolean wide;
int ref;
LabelOperand(Label l, Insn source, int line)
{ target = l; this.source = source; this.wide = false; this.ref = line; }
LabelOperand(Label l, Insn source, boolean wide, int line)
{ target = l; this.source = source; this.wide = wide; this.ref = line; }
int size(ClassEnv ce, CodeAttr code) { if (wide) return 4; else return 2; }
void resolve(ClassEnv e) { return; }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
if (wide) { target.writeWideOffset(ce, source, out); }
else {
int offset = ce.getPc(target);
if (source != null)
offset -= ce.getPc(source);
if (offset > 32767 || offset < -32768)
throw new jasError
("reference from line " +ref+ " exceed size for short");
target.writeOffset(ce, source, out); }
}
}
class UnsignedByteOperand extends InsnOperand
{
int val;
UnsignedByteOperand(int n) { val = n; }
int size(ClassEnv ce, CodeAttr code) { return 1; }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
if (val >= 256)
throw
new jasError("Operand is too large (" +val+ ") for this instruction");
out.writeByte((byte)(0xff & val));
}
void resolve(ClassEnv e) { return; }
}
// This (conditionally) adds a wide
// prefix if the value is larger than
// 256
class UnsignedByteWideOperand extends InsnOperand
implements RuntimeConstants
{
int val;
boolean Wide;
UnsignedByteWideOperand(int n, boolean Wide)
{
val = n;
this.Wide = (Wide || val > 255);
}
int size(ClassEnv ce, CodeAttr code)
{ return Wide ? 3: 1; }
void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException
{
if (Wide)
out.writeByte((byte)(opc_wide));
}
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException
{
if (Wide)
out.writeShort((short)(0xffff & val));
else
out.writeByte((byte)(val & 0xff));
}
void resolve(ClassEnv e) { return; }
}
class ByteOperand extends InsnOperand
{
int val;
ByteOperand(int n) { val = n; }
int size(ClassEnv ce, CodeAttr code) { return 1; }
void resolve(ClassEnv e) { return; }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException
{ out.writeByte((byte)val); }
}
class IntegerOperand extends InsnOperand
{
int val;
IntegerOperand(int n) { val = n; }
int size(ClassEnv ce, CodeAttr code) { return 4; }
void resolve(ClassEnv e) { return; }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException
{ out.writeInt(val); }
}
class ShortOperand extends InsnOperand
{
int offset;
ShortOperand(int n) { offset = n; }
void resolve(ClassEnv e) { return; }
int size(ClassEnv ce, CodeAttr code) { return 2; }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException
{ out.writeShort((short)offset); }
}
class CPOperand extends InsnOperand
{
CP cpe;
boolean wide;
int size(ClassEnv ce, CodeAttr code) { if (wide) return 2; else return 1; }
CPOperand(CP cpe) { this.cpe = cpe; wide = true; }
CPOperand(CP cpe, boolean wide)
{ this.cpe = cpe; this.wide = wide; }
void resolve(ClassEnv e)
{ e.addCPItem(cpe); }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
int idx = e.getCPIndex(cpe);
if (wide)
{ out.writeShort((short) idx); }
else
{
if (idx > 255)
{ throw new jasError("exceeded size for small cpidx" + cpe); }
out.writeByte((byte) (0xff & (idx)));
}
}
}
// these are unique enough that
// they need a separate handler for their
// args
class LdcOperand extends InsnOperand implements RuntimeConstants
{
CP cpe;
Insn source;
boolean wide;
int size(ClassEnv ce, CodeAttr code) throws jasError
{
if (wide)
{ return 2; }
else
{
// Should we promote it?
int idx = ce.getCPIndex(cpe);
if (idx > 255)
{
wide = true;
source.opc = opc_ldc_w;
return 2;
}
return 1;
}
}
LdcOperand(Insn s, CP cpe) { source = s; this.cpe = cpe; wide = true; }
LdcOperand(Insn s, CP cpe, boolean wide)
{ source = s; this.cpe = cpe; this.wide = wide; }
void resolve(ClassEnv e)
{ e.addCPItem(cpe); }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
int idx = e.getCPIndex(cpe);
if (wide)
{ out.writeShort((short) idx); }
else
{
if (idx > 255)
{ throw new jasError("exceeded size for small cpidx" + cpe); }
out.writeByte((byte) (0xff & (idx)));
}
}
}
class InvokeinterfaceOperand extends InsnOperand
{
CP cpe;
int nargs;
InvokeinterfaceOperand(CP cpe, int nargs)
{ this.cpe = cpe; this.nargs = nargs; }
int size(ClassEnv ce, CodeAttr code) { return 4; }
void resolve(ClassEnv e)
{ e.addCPItem(cpe); }
void write (ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(cpe));
out.writeByte((byte) (0xff & nargs));
out.writeByte(0);
}
}
class IincOperand extends InsnOperand
implements RuntimeConstants
{
int vindex, constt;
boolean Wide;
IincOperand(int vindex, int constt, boolean Wide)
{
this.vindex = vindex;
this.constt = constt;
this.Wide = (Wide ||
vindex > 255 ||
constt > 127 ||
constt < 127);
}
int size(ClassEnv ce, CodeAttr code)
{
return Wide ? 5 : 2;
}
void resolve(ClassEnv e) { return; }
void writePrefix(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException
{
if (Wide)
out.writeByte((byte)opc_wide);
}
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException
{
if (Wide)
{
out.writeShort((short)(0xffff & vindex));
out.writeShort((short)(0xffff & constt));
}
else
{
out.writeByte((byte) (0xff & vindex));
out.writeByte((byte) (0xff & constt));
}
}
}
class MultiarrayOperand extends InsnOperand
{
CP cpe;
int sz;
MultiarrayOperand(CP cpe, int sz)
{ this.cpe = cpe; this.sz = sz; }
void resolve(ClassEnv e) { e.addCPItem(cpe); }
int size(ClassEnv ce, CodeAttr code) { return 3; }
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
out.writeShort(e.getCPIndex(cpe));
out.writeByte((byte)(0xff & sz));
}
}
class LookupswitchOperand extends InsnOperand
{
LabelOrOffset dflt;
Insn source;
int match[];
LabelOrOffset jmp[];
LookupswitchOperand(Insn s, LabelOrOffset def, int m[], LabelOrOffset j[])
{ dflt = def; jmp = j; match = m; source = s; }
void resolve (ClassEnv e) { return; }
int size(ClassEnv ce, CodeAttr code) throws jasError
{
int sz = 8; // 4 + 4 + padding + jumptable
int source_pc = code.getPc(source);
if (((source_pc+1) % 4) != 0)
{
// need padding
sz += (4 - ((source_pc+1) % 4));
}
if (jmp != null)
{ sz += 8*(jmp.length); }
return sz;
}
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
int pad;
int source_pc = ce.getPc(source);
if (((source_pc+1) % 4) != 0)
{ // need padding
pad = (4 - ((source_pc+1) % 4));
for (int x=0; x<pad; x++) out.writeByte(0);
}
// write offset to default
// as a 4 byte signed value
dflt.writeWideOffset(ce, source, out);
if (jmp == null)
{ out.writeInt(0); }
else
{
out.writeInt(jmp.length);
for (int x=0; x<jmp.length; x++)
{
out.writeInt(match[x]);
jmp[x].writeWideOffset(ce, source, out);
}
}
}
}
class TableswitchOperand extends InsnOperand
{
int min, max;
LabelOrOffset dflt;
LabelOrOffset jmp[];
Insn source;
TableswitchOperand(Insn s,int min, int max, LabelOrOffset def,
LabelOrOffset j[])
{
this.min = min; this.max = max;
dflt = def; jmp = j; source = s;
}
void resolve(ClassEnv e) { return; }
int size(ClassEnv ce, CodeAttr code)
throws jasError
// the *real* reason for making it a
// method..
{
int sz = 12; // 4+4+4+jmptable+padding...
int source_pc = code.getPc(source);
if (((source_pc+1) % 4) != 0)
{ // need padding
sz += (4 - ((source_pc+1) % 4));
}
if (jmp != null)
{ sz += 4*(jmp.length); }
return sz;
}
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError
{
int pad;
int source_pc = ce.getPc(source);
if (((source_pc+1) % 4) != 0)
{ // need padding
pad = (4 - ((source_pc+1) % 4));
for (int x=0; x<pad; x++) out.writeByte(0);
}
dflt.writeWideOffset(ce, source, out);
out.writeInt(min);
out.writeInt(max);
int cnt = jmp.length;
for (int x=0; x<cnt; x++)
{ jmp[x].writeWideOffset(ce, source, out); }
}
}
class OffsetOperand extends InsnOperand {
int val;
boolean wide;
Insn parent;
OffsetOperand(Insn parent, int val) {
this(parent, val, false);
}
OffsetOperand(Insn parent, int val, boolean wide) {
this.parent = parent;
this.val = val;
this.wide = wide;
}
void resolve(ClassEnv e) { return; }
int size(ClassEnv e, CodeAttr ce) {
return wide ? 4 : 2;
}
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError {
if(wide)
out.writeInt(val);
else
out.writeShort(val);
}
}
class RelativeOffsetOperand extends InsnOperand {
int val;
boolean wide;
Insn parent;
RelativeOffsetOperand(Insn parent, int val) {
this(parent, val, false);
}
RelativeOffsetOperand(Insn parent, int val, boolean wide) {
this.parent = parent;
this.val = val;
this.wide = wide;
}
void resolve(ClassEnv e) { return; }
int size(ClassEnv e, CodeAttr ce) {
return wide ? 4 : 2;
}
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
throws IOException, jasError {
if(wide)
out.writeInt(val);
else
out.writeShort(val);
}
}
/* --- Revision History ---------------------------------------------------
--- Iouri Kharon, Aug 10 2006
Added 'Wide' prefix support to IincOperand and UnsideWideOperand
*/

View file

@ -0,0 +1,32 @@
package jas;
import java.io.*;
/**
* Wrap an integer constant reference with this CPE.
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
public class IntegerCP extends CP implements RuntimeConstants
{
int val;
/**
* @param n Value for integer constant
*/
public IntegerCP(int n)
{
uniq = ("Integer: @#$" + n).intern();
val = n;
}
void resolve(ClassEnv e) { return; }
void write(ClassEnv e, DataOutputStream out)
throws IOException
{
out.writeByte(CONSTANT_INTEGER);
out.writeInt(val);
}
}

View file

@ -0,0 +1,43 @@
/**
* An InterfaceCP is used to refer to an interface specification
*
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class InterfaceCP extends CP implements RuntimeConstants
{
ClassCP clazz;
NameTypeCP nt;
/**
* @param cname Name of class defining the interface
* @param varname symbol for the interface method
* @param sig Signature for method
*/
public InterfaceCP(String cname, String varname, String sig)
{
uniq = (cname + "&%$#&" + varname + "*()#$" + sig).intern();
clazz = new ClassCP(cname);
nt = new NameTypeCP(varname, sig);
}
void resolve(ClassEnv e)
{
e.addCPItem(clazz);
e.addCPItem(nt);
}
void write(ClassEnv e, DataOutputStream out)
throws IOException, jasError
{
out.writeByte(CONSTANT_INTERFACEMETHOD);
out.writeShort(e.getCPIndex(clazz));
out.writeShort(e.getCPIndex(nt));
}
}

View file

@ -0,0 +1,21 @@
/**
* Some instructions are perniticky enough that its simpler
* to write them separately instead of smushing them with
* all the rest. the invokeinterface instruction is one of them.
* @author $Author: jonmeyerny $
* @version $Revision: 1.1 $
*/
package jas;
import java.io.*;
public class InvokeinterfaceInsn extends Insn implements RuntimeConstants
{
public InvokeinterfaceInsn(CP cpe, int nargs)
{
opc = opc_invokeinterface;
operand = new InvokeinterfaceOperand(cpe, nargs);
}
}

View file

@ -0,0 +1,73 @@
/**
* Labels are implemented as Insn's, but are special (read
* unseemly blobs of hacked up code). First, they don't
* actually cause any code to be written, and second, are
* identified globally through a String label that is associated
* with them when they are created.
* @author $Author: jonmeyerny $
* @version $Revision: 1.2 $
*/
package jas;
import java.io.*;
public class Label extends Insn implements RuntimeConstants
{
String id;
/**
* Create a new Label with this tag. Any label with this tag
* will be treated as being identical to this one. You can
* reuse labels if you like
*/
public Label(String tag)
{
id = tag.intern();
opc = opc_label;
operand = null;
}
// override the write method to do nothing.
void write(ClassEnv e, CodeAttr ce, DataOutputStream out)
{ return; }
// and the size method appropriately
int size(ClassEnv e, CodeAttr ce)
{ return 0; }
// This is called from the LabelOperand
void writeOffset(CodeAttr ce, Insn source, DataOutputStream out)
throws jasError, IOException
{ // write the offset (as a short)
// of source
int pc, tpc;
pc = ce.getPc(this);
if (source == null)
tpc = 0;
else
tpc = ce.getPc(source);
short offset = (short) (pc - tpc);
out.writeShort(offset);
}
void writeWideOffset(CodeAttr ce, Insn source, DataOutputStream out)
throws IOException, jasError
{
int pc, tpc;
pc = ce.getPc(this);
if (source == null)
tpc = 0;
else
tpc = ce.getPc(source);
out.writeInt(pc - tpc);
}
public String toString()
{
return ("Label: " + id);
}
// method for StackMapFrame attribute (jdk1.6)
int getOffset(CodeAttr ce) throws jasError
{ return (short)ce.getPc(this); }
}

View file

@ -0,0 +1,39 @@
/*
* The purpose of this class is to have a generic type
* for labels and offsets, used by tableswitch and lookupswitch
*
*/
package jas;
import java.io.DataOutputStream;
import java.io.IOException;
public class LabelOrOffset {
private Label label;
private int offset;
public LabelOrOffset(Label l) {
label = l;
}
public LabelOrOffset(int o) {
offset = o;
}
Label getLabel() {
return label;
}
int getOffset() {
return offset;
}
void writeWideOffset(CodeAttr ce, Insn source, DataOutputStream out)
throws jasError, IOException {
if(label!=null)
label.writeWideOffset(ce, source, out);
else
out.writeInt(offset);
}
}

Some files were not shown because too many files have changed in this diff Show more