DrDialog, or: How I learned to stop worrying and love REXX - Part 8
By Thomas Klein
When I initially came up with the idea of this series, I wanted it to be suited for beginners - including beginners in REXX. Except for some minor parts, we only discussed objects and methods in DrDialog so far but did not actually start to do deal with REXX itself. Today, we'll put aside the "GUI stuff" and focus on an introduction to pure REXX on OS/2. Thus, if you're not a newby to REXX on OS/2, you're allowed to skip this issue ;)
Where to start
In this part, we'll take a look at what's special with REXX regarding variables and some basic commands and functions. In order to avoid the necessity of writing scripts that contain just one or two lines to test REXX's behaviour, we will rely on a great tool to "play" with REXX. It's called REXXTRY and should be easily callable from command-line on your system. Just go ahead, open a command line session (an OS/2 window) and type rexxtry. If you happen to have Ulrich Moeller's XWorkplace installed along with the XCenter button, you could use the Run... menu option from it as well and simply enter rexxtry in there. In either case, you should be presented with something like this:
If rexxtry won't come up, you might need to check if it's installed in a directory that is part of the PATH variable defined in config.sys. Or - to put it another way - you might need to run it from within the directory it is installed in. Search for a file named rexxtry.cmd. By default, it resides in the OS2 directory of your OS/2 installation drive.
Rexxtry can be used in several ways depending on how it was invoked. In our example, we just call it without any additional parameters which results in the "interactive mode" used to start from scratch and interpreting each input line from the user one by one.
To terminate the rexxtry-session, simply enter exit. By the way: As always, inputs are completed by pressing the Enter key...
Say hello or "hello"...
To start with something special about REXX, we'll try to say hello by code, using the say command.
say is used to "write an expression to standard output". As we're using the interactive rexxtry tool with no special tricks, the "standard output" device in our case is the screen - thus, we're displaying stuff. But what about "expression"? Simply speaking, this can either be a literal (a string enclosed in quotes), a variable or a function. In the latter cases, the content of the variable or the value of the function will be displayed.
To start with something finally, let's say hello by entering
This will result in a single output line of hello along with the dotted separator line provided by rexxtry (we'll ignore this one from now on).
What is so special in a funny way, is that REXX's interpreter is a very helpful guy. If you would write
this would mean: Display the contents of the variable named hello - simply because there where no quotes around the string. Actually, one would expect an error message popping up, telling that there is no such variable defined. And actually, this is right. But... instead, REXX will evaluate it as an expression, and because there is no variable named hello, it takes it as it is and simply displays:
Oops! That's the special thing... of course, things are what they are supposed to be again, if we provide a variable named hello. First, enter
hello = "Hi!"
...and as expected, this will give us
Because now, there is a variable called hello and REXX displays its content (which is Hi!).
You might have used other programming languages before and you know that they differ in the way that simple output to the screen are formatted, especially when dealing with output that consist of literals and variables put together. REXX is no exception to that rule as it is quite "precise" in interpreting the expression "behind" the say keyword. Let's go on by entering the following lines:
mol = 42 say "The meaning of life is:" mol
This will show
The meaning of life is: 42
You might wonder what is special about that... well, there is a space between the colon and the 42. Did we say to do so? I'm afraid we did - to make things clear, type
say "The meaning of life is:"mol
This will give you
The meaning of life is:42
And - by using a final example - using the command
say "The meaning of life is:" mol
(with 7 spaces between the literal and the variable name) will result in an output of
The meaning of life is: 42
The number of spaces used in the say command is exactly the same that is used in the output formatting, which is not typical for programming languages in general AFAIK. Usually, the command is parsed into a keyword and parameters part only and the number of spaces between them is ignored.
Now that we already know a way of doing outputs, let's look on a REXX command used for doing inputs. We'll use the PULL command to read user inputs. Actually, PULL is used to read a line from the "standard input" queue. Again, as we didn't mess with other ways of using queues up to now in our rexxtry session, this will make REXX wait for an input line from the user (terminated by the return key). Go on by entering:
Rexxtry will now wait for your input. Just type any sentence that comes to your mind, but make sure it's using lower case letters (in parts at least). Then type
And you'll see that your input was turned uppercase. That's the way it is - if you want to get it back exactly as it was entered, you have to rely on another function named PARSE used in conjunction with PULL like in:
parse pull input
will give you exactly what you typed in. Of course, there's a lot more to mention about PARSE but we'll look into details of it in a later part.
Okay, so far we know basic input and output commands in REXX. Unfortunately, they won't be of use in DrDialog programs, as its environment doesn't allow the use of these functions - why should it on the other hand? In DrDialog we do displays by setting a control's text and doing inputs by retrieving an entry field's content. The say command can be very useful in DrDialog to check your programs behaviour as it can only display things in the run time monitor window. But both say and pull will allow you to do some basic REXX scripts outside DrDialog as well. Anyway: For now, we should get on by taking a look at elements of REXX that we'll deal with in DrDialog as well. Let's see how arithmetic operations are done in REXX.
How to oneplusone
In REXX, most arithmetic operations are done by simply specifying a formula using the common notation of PLUS(+) and MINUS(-) signs, an ASTERISK(*) for multiplication and a SLASH(/) for divisions. As always, the common principles of algebra apply - that's to say, calculation is done from left to right with expressions in parenthesis being calculated first, as well as multiplication and division will precede any adding or subtracting operation. Some examples:
- Adding values
result = 12 + 4
result will contain 16
- Increasing a variable's value by 1
result = result + 1
The value of result will be increased by 1
result = a - 5
Result will contain the value of the variable a decreased by 5
cents = dollars * 100
cents will contain the value of the variable dollars multiplied by 100
dollars = cents / 100
The same way back: The variable dollars will contain the value of the variable cents divided by 100
- "Complex" function:
say 100 + 17 * (3 - 1)
This will display 134: The multiplications precedes the addition with the value in parentheses being calculated first...
Not that some of the examples above are taken from a kind of larger context: Increasing a variables value by 1 requires the variable to contain a numeric value prior to do the increase as it'll give you an error otherwise. The same applies to result = a - 5: The contents of a must be numeric prior to it. In rexxtry for example, you could do it like that:
cents = 3456</tt>
dollars = cents / 100
...which will display 34.56. Exponential calculation by the way is done by using double asterisks like in
<tt>say "The maximum decimal value stored in a single byte is" 2 ** 8 -1</tt>
Quotes and comments
Let's take a look at comments first. Comments are used to store information within a program source (or a script) that are not intended to be processed by the compiler or interpreter. They are used to comment certain parts of a program, in order to ease the understanding of the code. One thing is special about comments in REXX - that is, the first line of a REXX program must be a comment. I once read that this is used by OS/2 to distinguish between a REXX script and a batch command file, but I'm not sure if this is correct.
Anyway - take it as it is: A REXX script in OS/2 has to start with a comment. (In DrDialog however there is no need to do so, because the code you write will actually be embedded in a kind of code frame provided by DrDialog's environment.) A comment is initiated with the sequence /* (slash asterisk) and is terminated by the reverse notation */ (asterisk slash). Thus, a comment on a single line would look like that:
/* this is a comment */
Comments can span multiple lines too - as an example, such comment would be something like...:
<tt>/* the following routine is invoked each time a line was read from the input file. Each string within the line that matches the search criteria is removed. The rest of the line is then written to the output file. The number of strings found in the line is returned to the invoking routine by means of return code. */ </tt>
If the comment spans various lines of code, it becomes quite difficult to distinguish comment from code at first sight. Thus, most often, you'll find large comments in REXX files done in another way - programmers rather prefer to use multiple lines of one-line-comments like...:
/* the following routine is invoked each time a line was */ /* read from the input file. Each string within the line */ /* that matches the search criteria is removed. The rest */ /* of the line is then written to the output file. The */ /* number of strings found in the line is returned to */ /* the invoking routine by means of return code. */
The reason for programmers preferring this kind of commenting is its better readability: Such block of comments is more easily identified to be actual "comment" than multiple lines which have only ONE starting comment sequence and ONE ending sequence that might not be visible without prior scrolling down the code. Comments do not need to be the only part of a line. Quite often, you may want to just do a short comment for a single line of code and you're free to mix code and comment on a single line like in...:
euros = marks / 1.95583 /* convert former 'german marks' to euros */
Now let's see if there is something to be mentioned about quotes. REXX does support both single and double quotes. Thus, the two following lines are equal in matters of output:
say "hello" say 'hello'
The only thing you have to make sure is that quotes must match, otherwise REXX won't recognise them and will give you a "unmatched quote or *" error message... for example, if you would code a command like...:
The capability of REXX handling both types of quotes comes in handy if you want to display strings that actually contain quotes like...
say "The file specified doesn't exist"
say 'My boss said: "We need to re-focus on core competencies." '
But even provided with such great understanding by the interpreter, you might find yourself in a situation that requires you to use the same quotes in your string that you used to "put around" the string. In REXX this can be accomplished by doubling the quote (either single or double quote) inside the string. Hmm. Sounds difficult - here's an example:
say 'Bruce Hornsby says: "Thats just the way it is." and hes right.
I would suggest you to play around with quotes in <tt>rexxtry to get an impression of how things work.
What's coming up next?
Well, that's it for today. Next month, we'll talk about conditional expressions (if, select), iterative structures (loops), subroutines and functions. Part 10 will deal with REXX'S wealth of string manipulating functions and some of the RexxUtil functions. Then, Part 11 will take us back to DrDialog-specific matters by digging into using multiple dialogs within a program. I'm not sure whether part 12 will start the sample application work or rather will cover things I forgot up to now... we'll see - stay tuned!