March 16, 2003 Douglas Clark is a program management consultant who first started using OS/2 version 1.3. He's married, with 2 girls, and is old enough to remember when 4 color mainframe terminals were a big thing. If you have a comment about the content of this article, please feel free to vent in the OS/2 eZine discussion forums. There is also a Printer Friendly version of this page. |
|
Rexx: The King is Alive and Well
There was a period of time in the later 1990's
when one could question whether Rexx would be around much longer. IBM
released a white paper stating that its strategic direction on
scripting languages was changing to BASIC. IBM released its own
version of Visual BASIC for OS/2 and Windows and bundled Visual Basic
with release 5 of DB2. But the pretender to the throne died a sudden
and rapid death. IBM's version of Visual Basic quickly disappeared and
Rexx lives on.
| ||||||||||||||||||||||||
Rexx not only lives on but it gets stronger and stronger. While IBM was proclaiming the imminent death of Rexx, others were busy porting Rexx to different operating systems and hardware platforms. Today Rexx runs on a wide variety of platforms, from large mainframes to tiny PDAs. On OS/2, Windows, Linux and AIX a whole new object oriented version of Rexx was developed and released by, strangely enough, IBM. Why is Rexx becoming more and more popular? I think it is because Rexx has a number of outstanding features that make it an ideal scripting language. Rexx was designed to be more than just a programming language, it was designed to be scripting language. A scripting language is a language used by an application to provide a way to automate features or parts of the application, sometimes also called a macro language. The features of the Rexx language (no variable "types", easy to learn and use, etc.), along with the capabilities for extending the language and integrating the language into an application, make Rexx an outstanding language application "macro" language. This article looks at Rexx from the scripting or macro perspective. How the King is ExecutedBefore we can understand how Rexx can be used as a macro language we must first look at how Rexx programs are executed.In OS/2 when you open a Command Prompt window the operating system starts a program called the command processor, or CMD.EXE. The program processes the commands you type in the window. When you type a name or command that is not a Command Processor command (such as DIR, TYPE, etc.), the Command Processor assumes the name is the name of a program. The Command Processor appends one of the program file extensions (.BAT, .CMD, .COM, .EXE) to the name and searches for a file with that name. If the extension of the file ends in *.CMD the Command Processor reads the first line of the program to determine the type of program it is. If the first two characters of the file contain the characters /*, which is the start of a Rexx comment, the file is considered to be a Rexx program. It the first two characters are not /* the file is considered to be a batch file. If the file is a Rexx program the Command Processor loads the Rexx interpreter and passes the name of the file, along with any arguments, to the Rexx interpreter. The Rexx interpreter is a dynamically linked library, called REXX.DLL. Rexx programs are started by loading REXX.DLL into memory and calling the function RexxStart(). The RexxStart() function executes the Rexx program and returns when the Rexx program completes, or when it terminates because of an error. When Rexx is used as the macro language for an application it is the application that loads the Rexx interpreter REXX.DLL and calls the RexxStart() function instead of the OS/2 Command Processor. Any program that can call C type functions from an OS/2 DLL can execute Rexx programs. However simply giving a application the ability to start a Rexx does not make Rexx a macro language. The Rexx program needs to have some way of interfacing with the application in order to act as a macro to the application. For example if Rexx were to be used as a macro language in a text editor the Rexx program would need the ability to delete text and insert text into the file being edited, to save the file being edited, to load new files, etc. Rexx provides the following ways of interfacing a Rexx program with an application.
External functions are functions written in some other language, usually C, that can be called from a Rexx program. Subcommand handlers are routines written in another language that are called by the Rexx interpreter when a non-Rexx command is encountered in a Rexx program. System exit handlers are routines written in another language that are called by the Rexx interpreter when certain Rexx commands are encountered in the program, or during certain program events, such as program start-up, termination, etc. The Rexx variable pool is where Rexx stores its variables; external functions, subcommand handlers and system exit routines can create, read and write Rexx variables through the variable pool interface. SOM classes are classes created by the application which Object Rexx can call through its SOM interface; they pertain only to Object Rexx type programs. We will look at each of these ways of "extending" Rexx in the sections below. Rexx programs are started with the RexxStart() function in Rexx.DLL. The syntax is: rc = RexxStart(ArgCount, ArgList, RexxProgramNameOnDisk, RexxProgramNameInMemory, subCommandName, programType, systemExits, ReturnCodeAsInteger, ReturnCodeAsString) Where
The RexxStart() function does not return until the Rexx program finishes running. External FunctionsExternal functions are functions written in some other language that can be called from Rexx just like "normal" Rexx functions. Usually the other language is C, but it can be Pascal or any language that can follow C function calling conventions. For example Sibyl, the Pascal development tool, has a Pascal interface to the Rexx API. (The Rexx API is a set of functions and header files that provide programs or applications with the ability to start Rexx programs, and build external functions, along with subcommand handlers and system exit routines.)External functions are the most common method of extending Rexx. On OS/2, and on the Windows version of Object Rexx, Rexx comes with a set of external functions called RexxUtil that provide an interface to the operating system. In addition almost all the OS/2 system services are "exposed" to Rexx using external functions that a Rexx program can call. External functions are "packaged" into a file, either a *.DLL or an *.EXE file. There can be one function in the file or many functions in the file. Each of the external functions must be "registered" to Rexx before they can be used. For example if there are 50 external functions in a single DLL, all 50 functions must be registered with Rexx before they can be used. Since it would be a burden to the Rexx programmer to have to register each and every function he wanted to use, most function packages include a function that registers all the other functions. The registration tells Rexx what the name of the function will be called in Rexx, which file contains the function (*.DLL or *.EXE) and what the name of the function is in that file. The registration can take place in the external language using the Rexx API, or in the Rexx program itself using the built-in function RxFuncAdd(). The differences between registering the external function in the external language and registering it in Rexx are:
The Rexx API used by an external language to register a function looks like this. RexxRegisterFunctionDll(functionNameinRexx, moduleNameThatContainsFunction, nameOfFunctionInModule);or RexxRegisterFunctionExe(functionNameinRexx, moduleNameThatContainsFunction, nameOfFunctionInModule);An example is: The built-in Rexx function RxFuncAdd() looks like this rxFuncAdd(functionNameinRexx, moduleNameThatContainsFunction, nameOfFunctionInModule);An example is: Normally the name the function is called in Rexx and the name of the function in the external function file (the *.DLL or *.EXE) are the same. But there are times when the name in Rexx will need to be different than actual name of the function in the external function file. For example DB2 and Oracle both supply external Rexx functions for interfacing with their databases. Unfortunately both companies use the same names for some of their functions, for example both have a function named SQLEXEC(). If the ability did not exist adjust the name the function is called in Rexx it would be impossible for a single Rexx program to interface to DB2 and Oracle at the same time. Since the names of the functions as known in Rexx can be changed, the DB2 function could be registered to Rexx as SQLEXEC_DB2() and the Oracle function could be registered as SQLEXEC_ORA() and both could be used in the same Rexx program. The example below registers the function wdPluginLoad from the module WDPLUGIN.DLL as the function heyYou in Rexx. According to the Rexx API documentation, external functions registered with RexxRegisterFunctionDll are available to any Rexx program after they are registered, while functions registered with RexxRegisterFunctionExe are only available to Rexx programs invoked from the same process that registered the function. Applications using Rexx as a macro language, and that use external functions as an interface between the application and Rexx, should code the functions in the application module (either in the EXE or in a DLL loaded by the application) and should use RexxRegisterFunctionExe to register those functions before the application starts the Rexx program/macro. The example below shows Rexx functions being registered, the Rexx program being executed, and the functions being deregistered. Roger Orr's most excellent articles on Rexx (and other stuff) have example programs that show how to write external functions, and subcommand handlers and system exit routines. They can be found at http://www.howzatt.demon.co.uk Subcommand HandlersA Subcommand handler is a routine written in another language that is called by the Rexx interpreter when Rexx encounters a command that is not a normal Rexx command. The language is designed so that any command not recognized by the Rexx interpreter is passed to a (sub)command handler. The default subcommand handler is CMD, which passes the commands to the OS/2 Command Processor. This is why you can write lines likeSubcommand handlers, like external functions, can reside in their own DLL, or can be coded into an application, either in the EXE or a DLL loaded by the application. A subcommand handler must also be registered before it can be used, just like an external function. And just like external functions, the subcommand handler can be registered from inside the Rexx program, using the RxSubCom Rexx instruction, or from an external program using the RexxRegisterSubcomExe() or RexxRegisterSubcomDll() functions. The syntax for registering a subcommand handler from inside of Rexx is RXSUBCOM REGISTER nameOfHandlerInRexx nameOfDll nameOfRoutineInDLL The syntax for registering a subcommand handler from an external language is RexxRegisterSubcomDll(nameOfHandlerInRexx, nameOfDll, nameOfRoutineInDLL, userArea, whoCanDropHandler)The userArea is 8 bytes of unformatted memory that can used to store information the subcommand handler can use to determine which Rexx program is calling it. The whoCanDropHandler specifies if only the thread the registered the subcommand handler can deregister it, or if just anyone can deregister it. Once a subcommand handler has been registered it can be used by a Rexx program by specifying the subcommand handler's name in the Rexx ADDRESS instruction. Multiple subcommand handlers can be registered at the same time, and the Rexx program can switch between then while running with the ADDRESS instruction. Every Rexx program has a subcommand handler assigned, either the default handler or one that has been specified with the ADDRESS instruction. When an application starts a Rexx program with the RexxStart() function it can specify a subcommand handler to be the default subcommand handler, in the subcommandName argument of RexxStart(). The subcommand handler must be registered before it can be specified as a RexxStart() argument. Subcommand handlers are the most common way of providing an interface between a Rexx program running as a macro and the application. But external functions can also be used to provide that interface. Often times the choice between which of the two to use comes down a preference for the programming interface that will be used in Rexx. The differences between a subcommand handler and external functions are:
System Exit HandlersSystem exit handlers are routines written in an external language that are called when certain events happen in the Rexx program. These events include:
The exit handler can handle the event itself, ignore the event and let the Rexx interpreter take its normal action, or terminate Rexx. Exit handlers must be registered before they can be used. They must be registered by the application that will invoke the Rexx program before starting the Rexx program. The exit handler(s) are specified in the systemExits argument of the RexxStart() function. System exit handlers can be used to modify the way Rexx programs execute, or to control what a Rexx program is allowed to do. For example:
Variable Pool InterfaceAll three methods of extending Rexx - external functions, subcommand handlers, and system exit handlers - have an additional way of interfacing with Rexx. They can modify the Rexx variable pool. This means that the external functions can add new Rexx variables, delete or DROP existing Rexx variables, and change the value of existing Rexx variables. This gives applications using Rexx as a macro language a way of putting data into variables that Rexx can access, or reading Rexx variables that are set by the Rexx program.The application interfacing with the Rexx variable pool can address variables one of two ways:
Creating Rexx variables and putting values into Rexx variables is a powerful way of interfacing between an application and Rexx. SOM ClassesAll the method described above for integrating Rexx with an application - external functions, subcommand and system exit handlers, and the Rexx variable pool - are applicable to both classic Rexx and Object Rexx. However using Object Rexx as the macro language opens up possibilities for scripting applications with Rexx that area not available with classic Rexx.Object Rexx is an IBM created object oriented version of Rexx. It first appeared in Warp v 4, and was later ported to work with Warp v 3. Object Rexx adds a very complete object orientation to the familiar procedural Rexx that we all know, which is now called "classic Rexx". The beauty of Object Rexx is that the way it is implemented allows you to program either in the old, procedural way of classic Rexx, or in the new, object oriented way provided by Object Rexx. Even without using any objects at all, Object Rexx is a better Rexx than classic Rexx. It provides additional built-in functions that are available when writing procedural type Rexx programs, and it checks the syntax of the entire Rexx program before it starts running, so you know that all the branches of the program will not fail because of a syntax error. While Object Rexx is available for OS/2, Windows, Linux, and AIX, the OS/2 version has something the other versions don't: the ability to use SOM objects. With the OS/2 version of Object Rexx SOM object can be imported into a Rexx program so that they become full Object Rexx objects, just like ones created in Object Rexx. This opens up a whole new way of designing and structuring an application for scripting. Rexx programs with a way of using SOM objects. SOM objects can be imported into an Object Rexx program so that they appear to the Rexx program as "native" objects. This opens up a whole new realm of scripting possibilities, called object modeling. With object modeling, you analyze your application in terms of objects. Suppose your application is a server that uses TCP/IP sockets. One way to look at the communications is that each socket is an instance of a socket class. You could create a SOM class for sockets and SOM methods for the functions related to sockets, and then use those methods to interact with the socket objects. With object modeling you are still providing an interface between Object Rexx and the application, but that interface is through SOM objects rather than the more traditional methods described in the section above. The advantage of providing an interface through SOM objects is that any language that can interface to SOM can be used as the scripting language, which on OS/2 means C/C++, Java, and of course Object Rexx. The next step up from object modeling is to actually factor the application into objects, meaning that the SOM objects aren't the interface between the application and the Rexx, but the application itself. In other words the application is built from SOM objects. The user interface part of the application is separated from the functional part. The function part is built using SOM, and the both the user interface and the scripting languages interface to the functional part of the application the same way: by sending messages to the SOM objects, i.e. by calling methods of the objects. ConclusionRexx is not just a easy to use, easy to learn programming language that comes with OS/2. It is also a very powerful scripting language designed to be incorporated into applications. The interface, the Rexx API, which makes that interfacing possible, is a very well documented and very well supported API. Almost all Rexx interpreters on all platforms recognize the same Rexx API that is supported on OS/2 - known as the SAA Rexx API. Meaning that an application using Rexx as its scripting language can be developed on OS/2 and ported to other platforms and still keep the Rexx scripting feature.The King is certainly not dead; in fact he becomes stronger and
better looking all the time.
|
||||||||||||||||||||||||||
|