next up previous contents
Next: Personal Experience Up: Final Remarks Previous: Final Remarks

Conclusion

A relatively simple programming language like Pascal should not be too big a problem when you want to compile it to Java bytecode. The variable declarations are probably the most difficult part because Pascal has nested procedures and functions where all variables of the procedure or functions containing these nested procedures or functions should be accessible.

Because nested procedures or functions have to be compiled as if they were global methods the only option seemed to be to declare the local variables global as well. This way they can be used in the nested functions. The problem with this is that in recursive calls of procedures or functions the same global variables are used in every `instance' of the procedure or function. This may produce wrong results because values of one instance can be overwritten by another instance while the first instance still needs it.

This problem was solved by making local variables local and passing them as call-by-reference parameters to every nested procedure or function so they can be used there as well. For the same reason parameters of a procedure or function that were first compiled into global variables, were later compiled into local variables and passed as call-by-reference parameters to every nested procedure or function. The same goes for the internal variables of a function that contain the function result and the boolean to check if the function result was set.

Because procedures and functions in Pascal can have call-by-reference parameters, and neither Java nor the Java bytecode has a way to implement these, variables of primitive types had to be compiled as if they were arrays of one element. This way every variable had a reference that could be passed in case the variable was passed as an actual call-by-reference parameter to a procedure or function. In case of a call-by-value parameter, the value of the expression that is the actual parameter was passed. When this value is received by the method, it is a normal Java variable which has no reference. This meant we had to make a new variable that was an array and initialize it to the value. This variable was used instead of the normal variable.

For convenience reasons constants were also compiled into arrays of one element, even though they did not need a reference. This meant the value of the constant had to be put in the array somewhere. The <clinit> method proved to be the perfect place to do this. This is the same place where all the arrays are created and the references to these arrays stored in the appropriate variable.

Library procedures had to be used to handle I/O. The library procedure to handle write and writeln statements that write to standard output were given. For the read and readln statements and writing to and reading from files library procedures have to be made in the same manner.

Another problem was the fact that the bytecode has no labeling itself. For this an algorithm had to be designed. This algorithm sets internal labels from which the offsets for the jump instructions are resolved once they are known. Solutions were provided for every conditional statement.

The difference between function returns in Pascal, where the function result has to be assigned to the function identifier, and the Java bytecode that returns the value with a return statement, was solved by using two internal variables. The first variable was used as the variable to assign the function result to. The second variable was a boolean variable that was used to check at runtime if there was a function result stored in the first variable. If there was no function result to return from a function, an exception was thrown after which the program halted.

For each recordtype declaration a separate class with the name of the recordtype had to be made. This class, containing the fields of the record, was written to a class file. Every variable of the recordtype was now an instance of this class.

Because variables of primitive types, recordtypes and arraytypes already had references to them, pointers to variables were not a problem, and were almost solved implicitly.

Exceptions can be used to handle goto statements that cause a non-local jump. A procedure or function had to throw an exception containing the target label if this label is not in the code of the procedure or function. This exception was caught by the procedure or function that did have the label in its code, and the jump could be made by the exception handler.

This document described how to compile the non-trivial elements of the Pascal language. Compilation of every other element of the language that is not covered here can be solved by using the ideas and methods for compilation of the elements that were described.



next up previous contents
Next: Personal Experience Up: Final Remarks Previous: Final Remarks



mark@bottom.xs4all.nl