We have already encountered paragraphs during our discussion of the UniVerse editor. The FLUFFY
record was a paragraph, if not a very useful one.
A paragraph is UniVerse's equivalent to an MS-DOS 'batch file' or UNIX 'script'. MS-DOS batch files are rarely more than lists of commands to be executed in a certain order. UNIX scripts, on the other hand, are often intelligent routines, containing their own variables, decision making and looping structures. UniVerse paragraphs lie somewhere between the two, but are rather nearer the MS-DOS end of the spectrum than the UNIX end. Complex processing is almost exclusively done in UniVerse Basic.
At its simplest, then, a UniVerse paragraph is simply a list of UniVerse commands, written exactly as they would be typed at the UniVerse command prompt, such as FLUFFY. However, there are a few ways in which they can be made more flexible and useful. For example:
ED VOC RECLAIM
2 lines long.
----: P
0001: PA
0002: RESIZE <<I2,Enter filename to RECLAIM>> * * * CONCURRENT
Bottom at line 2.
----: Q
This paragraph illustrates a device called an in-line prompt. In-line prompts make paragraphs more useful by allowing you to prompt for details of the commands be executed at run time. In the example above, the standard UniVerse command RECLAIM
simply uses RESIZE
to resize a file without changing its type, modulo or separation: hence the * * *
parameters (for details of the RESIZE
command, see Static Files above). As was mentioned during the discussion of the RESIZE
command, this has the effect of reorganising the file internally and reclaiming pockets of unused space created during the addition and deletion of records into groups.
The interesting thing here, of course, is that the creator of the paragraph could not know in advance which file the user would wish to reclaim. Instead of specifying a file name, therefore, he used the <<...>>
syntax to create an in-line prompt.
The I2
before the comma in the inland prompt stands for Input word 2. It means that if the user enters the command RECLAIM CUSTOMERS
, the second word (CUSTOMERS
) will be substituted into the command, making the overall command RESIZE CUSTOMERS * * * CONCURRENT
. On the other hand, if the user simply enters RECLAIM
, the paragraph will display the following prompt:
RECLAIM
Enter file name to RECLAIM=
At this prompt, the user could enter CUSTOMERS
to reclaim the customers file.
Try it: make up a fictional file name if you don't want to sit and wait for RESIZE
to do its stuff. You'll get an error message reporting that your file name is invalid, but this will illustrate the principle just as well.
There are many different flavours of in-line prompt. The simplest form is just <<promptstring>>
. This ignores any parameters which may have been typed in on the command line and simply displays the prompt promptstring
to request a value from the user. Note that if more than one in-line prompt with the prompt promptstring
appears in your paragraph, the prompt promptstring
will only be displayed once, and the value entered will be used for them all.
This is usually helpful, but if you want to force a fresh prompt even if you are using the same prompt string, you can use the A,
prefix thus: <<A,promptstring>>
.
A variation on the In
prefix used by RECLAIM
(which you'll recall used the n
th word from the command line if it was there, but prompted for it if it wasn't) is the Cn
prefix. This also uses the n
th word from the command line, but evaluates to nothing (ie. an empty string) if it isn't. Sn
is subtely different again, using parameters not taken from the command line used to run the paragraph, but rather from the command line originally entered by the user. These are different when, say, the user enters the command PARA1 A B C
, and one of the lines in PARA1
is PARA2 X Y Z
. In this case, C3
evaluates to Y
, but S3
to B
.
If you need to substitute more than one value into your command, use R,
. This will prompt repeatedly until the user enters an empty value by hitting return. The list of values entered is then inserted into the command separated by spaces. This sounds worse than it is: an example should make it clear:
ED VOC ENTER.WORDS
Press RETURN
New record.
----: I
0001= PA
0002= DISPLAY You entered "<<R,Enter words>>"
0003=
Bottom at line 3.
----: FI
"ENTER.WORDS" filed in file "VOC".
The paragraph runs like this:
ENTER.WORDS
Press Return
Enter words=AREN'T
Enter words=IN-LINE PROMPTS
Enter words=WONDERFUL
Enter words=
You entered "AREN'T IN-LINE PROMPTS WONDERFUL"
If you wish to separate the words entered using an R
type in-line prompt with something other than a space, specify R(c)
where c
is the character you like to see between each entry. For instance, the result the paragraph above would have given if written with an R(*)
in place of the R
would have been:
You entered "AREN'T*IN-LINE PROMPTS*WONDERFUL"
Note that the space between the words IN-LINE
and PROMPTS
remains: this is because it was actually entered as part of the string, and not automatically added by the in-line prompt in response to RETURN.
You can jazz up your prompts using @(CLR)
to clear the screen before the prompt appears, @(BELL)
to sound the terminal bell when the prompt is displays, and @(col,row)
to position the prompt at column col
, row row
. You can use these in combination with each other, or the options above. For instance, try just typing in the following at the UniVerse command prompt:
DISPLAY You entered "<<@(CLR),@(BELL),R(*),Enter words>>"
This will clear the screen and beep, before repeatedly prompting Enter words=
until you press RETURN to enter an empty string, and finally display the words you entered separated by asterisks.
This last example illustrates an interesting point: in-line prompts are not restricted to use in paragraphs, but are actually features of the command language itself, and you can, in principle, use them in any command. It is unusual to use them in a directly entered command, but not unheard of. For instance, if you had to compile a large number of different records in the BP
file, you might enter the command:
BASIC BP <<Enter BP record key>>
Enter BP record key=PROGRAM1
Compiling: Source = 'BP/PROGRAM1', Object = 'BP.O/PROGRAM1'
*****************
Compilation Complete.
Why? Well, when you come to compile the next program, you can just...
.X
Enter BP record key=PROGRAM2
Compiling: Source = 'BP/PROGRAM1', Object = 'BP.O/PROGRAM1'
**********************************
Compilation Complete.
So in this case, the in-line prompts are stored as part of the stack, and when the command is re-executed, the in-line prompt is again used to find out which program you wish to compile. Neat, huh?
By typing in HELP
and using the cursor to select the <<...>>
topic, you can see the on-line documentation describing the use of in-line prompts, and learn a few other tricks not described here: but these are the most commonly used features.
You can add conditional logic to your paragraph using the IF
command. For instance:
ED VOC TEST.PARAGRAPH
Press RETURN
New record.
----: I
0001= PA
0002= IF <<Display something?>> = 'Y' THEN DISPLAY Ok, "something".
0003= Bottom at line 2.
----: FI
"TEST.PARAGRAPH" filed in file "VOC".
Try running this command twice, entering a Y
the first time...
TEST.PARAGRAPH
Display something?=Y
Ok, "something".
...and N
the second time...
TEST.PARAGRAPH
Display something?=N
While you can make a single line conditional in this way, IF
is more commonly used in conjunction with another command, GO
, which can cause the flow of execution to jump to another line of your paragraph.
The following example is typical:
ED VOC TEST.PARAGRAPH.2
New record.
----: I
0001= PA
0002= IF <<(E)nglish or/o e(S)pañol?>> = 'E' THEN GO ENGLISH.MESSAGE
0003= IF <<(E)nglish or/o e(S)pañol?>> = 'S' THEN GO SPANISH.MESSAGE
0004= DISPLAY E or S only please/E o S solomente por favor
0005= GO END
0006= ENGLISH.MESSAGE:
0007= DISPLAY Hello!
0008= DISPLAY How are you?
0009= GO END
0010= SPANISH.MESSAGE:
0011= DISPLAY ¡Ola!
0012= DISPLAY ¿Como esta usted?
0013= END:
This paragraph prompts the user with a choice of language, and displays messages an appropriate message. It works well enough: but the problem is that if the user enters something other than an 'E' or an 'S', he is given no chance to correct his mistake: the paragraph displays an error message and terminates.
In attempting to solve this problem, you might be tempted to edit the paragraph until it looked like this:
0001: PA
0002: GET.LANGUAGE:
0003: IF <<A,(E)nglish or/o e(S)pañol?>> = 'E' THEN GO ENGLISH.MESSAGE
0004: IF <<(E)nglish or/o e(S)pañol?>> = 'S' THEN GO SPANISH.MESSAGE
0005: DISPLAY E or S only please/E o S solomente por favor
0006: GO GET.LANGUAGE
0007: ENGLISH.MESSAGE:
0008: DISPLAY Hello!
0009= DISPLAY How are you?
0010= GO END
0011= SPANISH.MESSAGE:
0012= DISPLAY ¡Ola!
0013= DISPLAY ¿Como esta usted?
0014= END:
Note the highlighted changes. First, a new prompt has been inserted above the language prompt. Secondly, an A,
has been added to the first in-line prompt, so that if it must be used again, the paragraph will force it to be displayed even though it has an existing value. Lastly, a GO
has been added to return the user to the prompt should the value he enters be invalid.
It all looks good. You can enter it and try it... or you can save yourself the trouble and read on, because it won't work. The problem is that GO
statements cause the UniVerse command processor to search down the paragraph for the appropriate label: if the label is above the GO
, it will not be found.
To allow you to repeat a section of a paragraph in the way being attempted here, you must use the LOOP
and REPEAT
commands: the former marking the beginning of the section you wish to repeat, and the latter marking the end. Rewriting the paragraph above using these new commands gives you:
0001: PA
0002: LOOP
0003: IF <<A,(E)nglish or/o e(S)pañol?>> = 'E' THEN GO ENGLISH.MESSAGE
0004: IF <<(E)nglish or/o e(S)pañol?>> = 'S' THEN GO SPANISH.MESSAGE
0005: DISPLAY E or S only please/E o S solomente por favor
0006: REPEAT
0007: ENGLISH.MESSAGE:
0008: DISPLAY Hello!
0009= DISPLAY How are you?
0010= GO END
0011= SPANISH.MESSAGE:
0012= DISPLAY ¡Ola!
0013= DISPLAY ¿Como esta usted?
0014= END:
The label and GO
which were used to try and create a loop in the previous paragraph are here replaced by LOOP
and REPEAT
. This paragraph will now work as expected.
Most languages which provide statements like LOOP
and REPEAT
also provide some kind of WHILE
or UNTIL
condition which tells the program when to exit the loop: UniVerse Basic, for instance, does. However, the UniVerse command language does not: LOOP
/REPEAT
loops will loop forever, or until you GO
to a label outside the loop: so be warned.