|
|
Karel J. Robot
|
|
A preprocessor that translates a simplified Java-syntax into 100% pure Java code.
The simplifications are penned by Joseph Bergin et al. in their manuscript
Karel J. Robot. This work was used in the basic course
"Basics of Computer Science I" winter 2001 and
winter 2002 at Darmstadt University of Technology.
Contents
Introduction
Karel J. Robot is an interesting approach for teaching object oriented programming using Java.
The manuscript is by Joseph Bergin, Mark Stehlik, Jim Roberts and Richard Pattis. For details
on Karel J. please refer to the
manuscript.
The manuscript uses some simplifications which I will describe later. Joseph
Bergin also offers a runtime environment for programming robots as described
in Karel J. Though you have to use pure Java then and can't take advantage of
the simplifications. My work is mainly a preprocessor which translates the simplifications
into pure Java.
After using the
first version of my preprocessor and
Mr. Bergin's runtime environment for the "Introduction
to Computer Science" lecture at the "Darmstadt University
of Technology", we found some shortcommings which I tried
to fix in a second version of the preprocessor. I also wrote a new runtime environment
whose premier advantage is its small interface. We only used Karel J. as an
introduction into Java, so we essentially used the first chapters. My new r.
e. only offers the most basic functionality which is actually all we used. I
also wrote a new r. e. to solve some problems we had with the graphic interface.
A third cause for rewriting it is that we assigned exercises using Karel
J. The new runtime environment will offer the correctors some help.
News
- A new version of the Simulator is available for download (afternoon Sep. 16. 2002) -
KarelSim.jar - KarelRT.jar
- KarelRTsrc.zip - sample.task
- Added the clone method to ur_Robot
- Now all constructors of robots have the signature (street, avenue, direction,
beepers)
- Now you can use non-absolute paths for the source files in the commandline
- Fixed the frontIsClear() method to return false if the robot faces the edge
of the world (i.e. west of the first avenue or south of the first street)
- I forgot to mention that I compiled the classes using the jdk 1.4. This
means you also have to use the virtual mashine of the jdk 1.4 to run the simulator.
I will work on this but it will take a while until a version for earlier jdk
releases is available.
- Now you can change the World implementation to be used via the commandline.
There is a new commandline option available:
-worldimpl <fully qualified
classname> .
- I added a manifest to the KarelSim.jar file. Now you can start the simulator
by
java -jar KarelSim.jar your.task , but only the current directory
and KarelSim.jar will be in the classpath then. If you want to add other directories
or archives, you still have to use java -classpath KarelSim.jar;inst;%CLASSPATH%
Simulator your.task
- Updated the sample.task file to use the right constructor (see above), too.
- Standard directory for instrumented and compiled files is now the current
directory. If you want to use another one, be sure to have it in your classpath.
- There still might be a problem in the file finding mechanism. If the simulator
looks for a class and finds a file which is named like the file, it stops
looking any further. If this file doesn't really contain the searched class
(which is possible if you don't use public classes) it might be a problem.
- I reprogrammed the file finding mechsanism. Now the "Karel"-Constructor
is not added if a the super class has a constructor with four ints as parameters
but if it is a direct or indirect subtype of ur_Robot. Also if you didn't
explicitely imported the "keareltherobot" package, the simulator
didn't work. That should be fixed now.
- There was an error in the commandline I gave as example to start the Simulator.
The right one is:
java -classpath KarelSim.jar;inst;%CLASSPATH% Simulator
your.task .
- I added the Robot class which is part of the original core by Mr. Bergin.
Features
The new preprocessor now parses the denoted file and all files containing depending
classes. It does that in similar ways as javac. You can only have one public
class per file (in that case the file also must have the same name as the class),
but you can have as many non-public classes per file as you like and they can
have any name you like. That might, though, cause problems finding some types
(it might be that my way of finding types is not always correct). The simplest
way of success is that you only have one class per file and name the file the
same as the class. The preprocessor finds files with the extensions ".java"
and ".task".
How it works
The Proprocessor makes several changes:
- Aadd "import kareltherobot.*;" to all files.
- Add kareltherobot.Directions to the implemented interfaces of all classes.
- If the superclass of a class has a constructor like (int, int, int,
int) this constructor is added, calling the super constructor. This is because
in the manuscript subtyping is explained without constructors. And as every
robot needs this kind of constructor it is simply added if it isn't there. (at
the moment, this is buggy. consider: A extends ur_Robot, B extends A. Then B
wouldn't get the constructor ... I will fix this soon).
- Every method without visibility modifiers is set to be public. Otherwise,
if the method is inherited and was originally public, javac would say, that
it is redefined with weaker access rights.
- The new loop-statement of the Karel J. language is replaced by a for-statement.
Variables of the form "_i" + some counter are used so be careful not to use
identifiers like this yourself.
- The task-declaration of the Karel J. language is used to create a class. It
is called KarelTask and the clock of the task declaration becomes the body of
its main method. This class is public and it is added to the file containing
the task. So don't put a task into a file containing a public class (I might
change this, though). If a class KarelTask already exists within the classpath
it might cause some confusion. If you encounter problems like changes you made
don't appear, please look for KarelTask.java or KarelTask.class files and delete
them.
How to use it
To use the preprocessor, you have to download this jar-archive.
It contains the Preprocessor and the runtime environment (which can also be
downloaded separately). To start the simulator type
the following: java -classpath KarelSim.jar;inst;%CLASSPATH% Simulator
your.task . This will cause the preprocessor to do its modifications
to all necessary files, write the changed files into directory "dist", compile
them and run the task in an empty world. You can use the following commandline
parameters:
-delay <milliseconds> | The delay between robot movements in milliseconds |
-instdir <path> | The directory to temporarily output instrumented files |
-world <file> | The name of the world file to be loaded at startup |
-streets <number> | The number of streets to be visible |
-avenues <number> | The number of avenues to be visible |
-d <path> | The directory where to place generated class files |
-sourcepath <path> | Specify where to find input source files |
-worldimpl <classname> | The World implementation to be used |
For you to get started, I prepared a sample Karel J. .task
file. The directory in which the instrumented files (i.e. the generated
java files) are put, must exist and must be included in the classpath (the default
"inst"). If the -d argument is used, the specified directory must also be within
the classpath. I will not make the source code of the simulator publicly available,
as I am using a framework, I am developing myself,
for the preprocessor. This framework is not yet ready to be published. You can
download the source of the runtime environment
though.
The runtime is very similar to the one by Mr. Bergin. Actually it should
be the same except for the missing parts and a few extensions that are merely
optional to use. I also put the classes in the same package which is for downwards-compatibility
reasons. I intend that the programs we used last year can simply run using
the new r. e. and that the original r. e. can be used with my new simulator.
For documetation on the api I will add a JavaDoc generated docu soon. You
can also refer to the the Karel J. pages which also include a
JavaDoc documention.
The main difference between both implementations is the World. In my implementation
World has most of the static methods the original one has, but it just delegates
them to an instance of a World-object which also can be accessed using World.getWorld().
It is a singleton and therefor only one instance per virtual machine exists.
Because World is really an object for me, other implementations of World can
be used. Actually two already exist. World is only offers the functionality
for keeping book about walls, beepers and robots. The GUIWorld offers a graphical
interface for presenting the world. The protected method "registerWorld()"
is used by subclasses of World to set themselves as the World-Object. This
should be done within the static initializer to load a World implmentation
by using 'Class.forName( "WorldImplementation" );' just like for JDBC drivers.
I will add some documentation on World implementation later. For now please
refer to the source code of the r. e. The simulator automatically selects
"GUIWorld".
Error messages
Where possible, my simulator mimics or uses javac or java behaviour. There
are three types of errors: syntax errors, semantic errors and runtime errors.
Syntax and semantic errors appear during compiletime. The error messages have
the following format: filename:line,column:message . Where filename
is given as url (using the simulator) and denotes the file within which the
error occurred, line and column name the position within this file. As my
simulator parses the code itself, the syntax errors appear during parsetime
of the simulator. That means, the simulator doesn't generate original javac
error messages for them. the error messages then name the token the parser
found and a list of tokens that were expected to find. After transforming
the code, it is printed into the specified directory and compiled using javac.
The error messages generated by javac are translated by the parser. I.e. the
original source file and the original position of the error are printed out.
If an error occurred within code that was generated by the simulator error
in generated code is printed as errormessage followed by the filename
and position where the error occurred. This doesn't denote the original file
but the generated one. Javac also prints the line within which the error occurred
in the error message. This code sample is taken from the generated file so
it might look different from the respective line in the original code. The
runtime errors (or exceptions) are not especially handled by the simulator
and thus the sourcecode positions given in runtime error messages always name
the position within the generated file.
As mentioned before, we don't want that the students use arrays. Also, as
Karel J. introduces the loop statement, the for statement should not be used
in Karel J. programs. Also the '&&' and '||' operators don't exist in the
Karel J. language. So my simulator warns if it encounters any of those language
constructs.
Customization
The graphic of my new runtime, also is completely based on .gif images.
So it can be completely customized. The images are within the jar archive.
This is simply a zip archive within which you can replace the .gif files.
The graphic routine seperates the world into rectangles which represent the
crosroads the robots move on. The images are always stretched to fit exactly
into such rectangles. You can use a transparent color. I suggest, you use
images of the same resolution and. The robot and beepers should not fill the
image and be centered. You need to put your customized images back into the
jar archive for the simulator to find them. If you think your images are nice,
please send them to me, I'll publish them on this page.
Unfortunately using .gif images introduced a new probley, I was not yet
able to solve. The images are loaded asynchronously and thus it may happen
that an image is not displayed the first time it should be.
Contact
I am still in the testing phase, but also I have some ideas of funtionality
I'd like to add. So if you tried this program and encountered problems or
have ideas yourself what is missing, please let
me know. Also if you miss something in this docu, please tell me. If you
are interested in the simulator please check this page regularly as it will
(hopefully) change a lot within the next time.
|