Page 2 of 4
REXX
One of my favorite languages, which never quite made the splash it deserved, was REXX, designed by Mike Cowlishaw of IBM.
The company needed a language to control applications on large mainframes running the VM operating system. I discovered REXX
on the Amiga where it was tightly coupled with a wide variety of applications through "REXX ports." These ports allowed applications
to be driven remotely via the REXX interpreter. This coupling of interpreter and application created a much more powerful
system than was possible with its component parts. Fortunately, the language lives on in NETREXX, a version Mike wrote that
was compiled into Java code.
As I was looking at NETREXX and a much earlier language (LISP in Java), it struck me that these languages formed important parts of the Java application story. What better way to tell this part of the story than to do something fun here -- like resurrect BASIC-80? More importantly, it would be useful to show one way in which scripting languages can be written in Java and, through their integration with Java, show how they can enhance the capabilities of your Java applications.
BASIC is, quite simply, a basic language. There are two schools of thought on how one might go about writing an interpreter for it. One approach is to write a programming loop in which the interpreter program reads one line of text from the interpreted program, parses it, and then calls a subroutine to execute it. The sequence of reading, parsing, and executing is repeated until one of the interpreted program's statements tells the interpreter to stop.
The second and much more interesting way to tackle the project actually is to parse the language into a parse tree and then execute the parse tree "in place." This is how tokenizing interpreters operate and the way I chose to proceed. Tokenizing interpreters also are faster as they don't need to re-scan the input every time they execute a statement.
As I mentioned above, the three components necessary to achieve dynamic execution are a means of being loaded, a module format, and the execution environment.
The first component, a means of being loaded, will be dealt with by a Java InputStream. As input streams are fundamental in the I/O architecture of Java, the system is designed to read in a program from an InputStream and convert it into executable form. This represents a very flexible way of feeding code into the system. Of course, the
protocol for the data going over the input stream will be BASIC source code. It is important to note that any language can
be used; don't make the mistake of thinking this technique can't be applied to your application.
After the source code of the interpreted program is entered into the system, the system converts the source code into an internal representation. I chose to use the parse tree as the internal representation format for this project. Once the parse tree is created, it can be manipulated or executed.