next up previous contents
Next: Acknowledgments Up: Final Remarks Previous: Conclusion

Personal Experience

This section describes the way the project went from beginning to end.

When I started in February 1997, I knew absolutely nothing about the Java Virtual Machine and I had only heard a few things about the Java programming language. Therefore the first thing I did was read [JVM]. This book covers all the details of the JVM, the class files and the JVM instruction set. Although the class files are fully described in the book, I found it hard to visualize what the precise contents of the constant_pool[] and other fields of the class file were. To view the contents of a class file, I first dumped all the bytes in hexadecimal form to a file. This way it was possible to see the class file byte by byte. The problem with this was, that if I wanted to find a specific field in this hex-dump, I had to go through all the bytes until I found the field I was looking for. If you made a small mistake in counting the bytes, you were looking at the wrong field.

I started looking for a program that outputs the whole class file in a way that it is possible to quickly find the field you need. I searched the Web for such a program, but I could not find what I needed. I did find the D-Java program written by Shawn Silverman, that shows you the class file as if it was a program written in Java bytecode. It did not show the contents of the constant_pool[], so it was not exactly what I was looking for. Later, when I generated code for Pascal programs, it proved to be a big help after all.

I also found the Jasmin program. Jasmin is an assembler that assembles programs written in Java bytecode to Java class files. D-Java also contains an option to output the class file in `jasmin' code. When writing a program in jasmin, you do not have to give the entries of the constant_pool[] yourself, the assembler constructs them for you. During the project I was really sorry that I did not compile Pascal to jasmin, instead of generating the class file myself. It would have saved me a lot of trouble constructing the constant_pool[]. On the other hand, by generating the class file yourself, you can specifically define every field it contains.

Although I found jasmin and D-Java, they were not what I was looking for. I decided to write my own program, jdisco. I wrote it to just output all the fields in the class file, it did not have to resolve the indexes to any of the fields. Later I regretted that I did not do that, as I had to do it myself. This is not much work with a small class file, but the bigger the class file, the more work it gets. I could have changed the program, but that would have probably been more work, so I could not be bothered.

It took me about one and a half month to know everything about the JVM I needed to know. In this time I wrote a lot of little testprograms to see how the javac compiler compiled some things.

After this period, I started on the compiler. I started out by designing the structures that had to hold most of the fields of the class file in memory during compilation. After doing this, I wrote the procedures that had to fill the class file with its minimum fields, so I could compile an empty Pascal program. This took me another few weeks. Believe me if I say that finding an error in a class file is not really nice work. When checking if a class file is correct, I ran it on the JVM. Most of the time, when there is an error, all the JVM says is ``can't find class whateveritsname''. That is a big help.

After being able to compile an empty Pascal program, I started working on the variables. It took me quite some time to get these right. At one point it almost looked like trial and error. Just when I thought I had them compiled the right way, I found something that did not work. One of the last days I was working on the compiler and ran some more tests, I found the problem described in subsection 9.1.3. I did not have enough time to implement the solution, so that is why you see the local variables still as global in the example described in appendix A. I did implement the parameters as local variables, but I do not pass them to the nested functions, I just did not have any more time.

Generating code for the statements was relatively easy compared to the problems I had with the variables. In a few weeks I was able to compile a program that could do quite a lot.

At the end of the project, when I was running some tests, I found some little errors (besides the local/global variable problem). Most of them could be solved very simply, and were things I simply forgot or thought I had done. There was one error I did not solve. This was that it is possible in Pascal to compare a value of type integer with a value of type real, or assign a value of one of these types to a variable of the other type. I did not know that. When you run a program that does this on the JVM, it will work, but if you use the -verify flag, to verify the class file before being run, the JVM complains. I did solve the problem with the assignments, by simply casting the rightvalue of the assignment to the type of the leftvalue. I did not solve the comparison problem, because it was not so easy to do because of the way the ACK Pascal compiler was structured, and I did not have time to do the restructuring of the compiler necessary to know when to cast or not.

As floats are stored in the constant_pool[] in IEEE 754 floating-point ``single format'' bit layout, I used the properties of the SPARC processor that also stores floats in this format. This means the compiler can only be used on this platform. To solve this you have to convert the float to this format manually. There must be some C library functions that can do this.

After I was able to compile programs containing write and writeln statements, I thought it would be a nice idea to implement the read and readln statements as well. As I was using JDK1.0.2, and the only functions available there were functions to read values byte by bytes, I did not think it was possible. With these functions, you could only read an integer from standard input by reading in four bytes. This meant that the user of a program had to divide the integer in 4 bytes before he typed it. My guess was that this was not really the way it should go.

Thanks to some people on the #java IRC channel, I found out that in JDK1.1.2 there were classes that could read characters from standard input. This only meant that you had to parse the characters typed yourself to construct values of type integer, char or real. I started writing the procedures for it, but soon I found it too much work for something that would definitely work, so I focused my attention to other more important things. This is why you can see the entries for the read and readln procedures of the library class in the constant_pool[] of the example program described in appendix A.

Because I used the Reader and Writer classes of JDK1.1.2 I also had to use the JVM of this package. The JVM of JDK1.0.2 could not find a class definition of these classes.

Looking back on the project, I must say I found it pretty interesting and most of the time very annoying when I could not think of a proper solution to a problem fast enough. It really helps to talk to someone else to hear his opinion. Often other people have a clear mind and can help you to view things from a different perspective while you are thinking about it so much that you keep thinking in circles.



next up previous contents
Next: Acknowledgments Up: Final Remarks Previous: Conclusion



mark@bottom.xs4all.nl