If you have only used interpreted languages, you may be unfamiliar with the idea of a build cycle. It is simply the series of steps you must take from writing your program to running it.
On the other hand, if your background is in a programming language like C you may be used to a very complex build cycle which involves editing, compiling, linking, make files, and so forth. The UniVerse Basic build cycle is, thankfully, far simpler than this.
Essentially there are three stages:
1. Editing your program.
2. Compiling your program.
3. Running your program.
These three stages are described below, and are followed by a few tricks to take the drudgery out of this routine.
If you are writing a 'shared' subroutine, to be called by other programs, there is a fourth stage known as 'cataloging' your program. This is described in the section on Basic External Routines below.
Each program you write will take the form of a record in a file: and it follows that you need to create a file to store your programs. Bear the following in mind:
1. Your program file must be a directory file (see Directory Files): UniVerse will refuse to compile records in any hashed file. A directory file is so called because it is implemented as a directory under Unix: and each record in it becomes a simple Unix text file. Type 19 files uses the record keys as Unix file names. Type 1 files build impromptu subdirectory structures designed to ensure that a filename is never over a certain length. Unless you have a good reason to use a type 1 file, therefore, I recommended the simplicity of a type 19 file. There are advantages to a simple Unix implementation, especially if you are using a Unix based source control system such as RCS.
2. If you are planning a large suite of programs, you may want to consider creating more than one program file and dividing your programs by function. There is no limit to the number of program files you can put in an account, though you need to strike a balance between functional separation and simplicity.
3. There is a well established convention amongst UniVerse developers that program files are either called BP
or suffixed .BP
. It's not a convention I'm crazy about, as I believe unnecessary abbreviations detract from readability, but on the other hand there's no doubting that most UniVerse programmers will instantly recognise the initials BP as standing for Basic Programs, so it is perhaps as well to do the same.
During this section, we will be creating onlya few programs, so a single file will suffice. Create your program file with the command:
>CREATE.FILE BP 19
??FB??
You have, by now, created dozens of records using the UniVerse editor, so you may be glad to hear that program records are created using the same tool. Incidentally, refer back to The Editor - ED if you are not throroughly familiar with the editor, as it will be used extensively in this section. If you have been using vi
you will be unable to implement the useful macros at the end of this section, or to use the vital editor command FORMAT
, which idents your code to show its structure. Yes, you could indent your code yourself, but (a) it takes time and (b) it would only reflect the structure you thought your code had, not the structure it really had if you had, say, forgotten to close your ELSE
BLOCK with an END
: more of this later.
For now, I shall follow the time honoured convention of making your first UniVerse program display the words Hello world!
on the screen. The PRINT
statement does the work, the END
marks the end of the program. All UniVerse Basic programs end in END
:
>ED BP HELLO.WORLD
New record.
----: I
0001= PRINT 'Hello world!'
0002= END
0003= (Press ENTER)
Bottom at line 2.
----: FORMAT
??FB??
----: P
??FB??
----: FI
Record "HELLO.WORLD" filed in file "BP".
>
The P
command above is not strictly necessary: but I wanted to show you what FORMAT
had done to your code. The 'standard' indent was applied to your first line, and the final END
was pulled in to the left. This pattern will become more and more meaningful to you as you gain experience writing and formatting programs.
Having written your program, you must compile it. Before discussing the command you must enter, it is perhaps worth explaining what happens when you compile a program.
If you were running a interpreted language, such as Dartmouth Basic, each line of your program would be read in turn, and converted into a series of numeric instruction codes which would be fed to your computer's CPU for execution.
A true compiled language, like C, is converted into numeric instruction codes before a single line of code is run. Once this has been done, the original C source code could, in theory, be thrown away: the computer merely executes the numbers. It is kept only because it is likely that the program may need to be changed in the future.
The UniVerse Basic approach lies somewhere between these two. The problem with compiling down to numbers suitable for a particular CPU is that CPUs, and the numbers they understand, vary from computer to computer, so code compiled on one machine cannot be run on another, and so a compiler capable of translating directly from source code to 'binary' code must be created for each machine.
In addition, whereas an interpreter contains many complex routines internally (and thus can employ them whenever they are required by the current instruction), a compiled language must include all the code for common activities in the binary code of any program which uses them.
To get round this, the original PICK was built on a 'virtual machine'. Dick Pick asked himself what functions the 'ideal' CPU would have for implementating his database. He then built a program which behaved like this 'ideal' CPU by translating instructions into the instructions undestood by the machine he was working on. In principle, this 'virtual machine' is the only part of an PICK system written in code specific to the CPU being used: the rest of PICK is written in PICK Basic, which is compiled into the numeric instructions required not by the underlying CPU, but by the 'virtual machine'. (I say in principle because some implementations cheat in certain places for efficiency reasons).
Thus, when PICK (or its later descendants) moved from computer to computer, only the virtual machine had to be rewritten for the new host. The rest of PICK continued using the same virtual machine, and thus the same numeric instruction set.
Pascal programmers may find this approach familiar as Pascal originally implemented a similar idea, with Pascal being compiled down to 'P code', which was then interpreted by a virtual CPU. Later Pascals, again for efficiency reasons, have largely abandoned the approach in favour of true compilation, but UniVerse retains the idea.
The numeric instructions used by the UniVerse virtual machine are known as 'op-codes', and the series of op-codes generated when you compile a UniVerse Basic program as 'beta code' or (in common with true compilers) 'object code'.
How much sense all this made to you will depend largely on your technical background. If it seems complicated, don't worry, because you can use UniVerse Basic without having to understand any of it: it is provided to satisfy the voracious technical appetite of C programmers to know what is going on 'under the bonnet'.
To compile your program, use the command:
>BASIC BP HELLO.WORLD
??FB??
>
Notice that BASIC
created a file called BP.O
. The O
stands for 'object code', and the object code for your program is stored in this file. This is because object code is one of the very few things in UniVerse which is not stored in ASCII, and programs like ED
get very confused when asked to load object code records. To reduce the possibility of this, a separate file is created to store it. You will see messages reporting the creation of a .O
file whenever your compile the first program in a new program file.
All that remains now is to run your new program. True to UniVerse's philosophy, the command to do this is what you'd expect it to be:
>RUN BP HELLO.WORLD
??FB??
>
This program is so simple that it is unlikely you would have to repeat the ED/BASIC/RUN
loop more than once to get it working correctly, but in real world examples you may find yourself doing it frequently.
If the cycle is perfectly even, you may find yourself typing .X3
again and again to reuse the appropriate commands from the stack (see The Command Stack): but you will eventually trip yourself up when your program doesn't compile, you therefore omit to run the program, and suddenly .X3
is no longer the right command. Even if your programs always compile without error (which planet are you from?) this approach still requires you to reinvoke ED
and find the line you were last working on each time round.
There is a useful alternative.
1. Use SAVE
to write your program to the file without leaving the editor (best to do this periodically anyway, so that next time a 'Machine being shut down in 5 minutes' message is delayed by 6 minutes by a busy network you don't lose too much work).
2. Still from the editor, use the command XEQ BASIC BP HELLO.WORLD
command to compile your program.
3. If your program compiled correctly, use the command XEQ RUN BP HELLO.WORLD
to test run it.
The beauty is that you need never leave the editor or lose your position in the record.
This can be made even easier by creating an editor macro:
ED &ED& BASIC.RUN
(Press ENTER)
New record.
----: I
0001= E
0002= SAVE
0003= XEQ BASIC @FILE @ID
0004= XEQ RUN @FILE @ID
0005=
Bottom at line 5.
----: FILE
If this macro seems familiar, it is because it first appeared in the section Editor Macros. If you followed the examples in that section, you may find this record already in your &ED&
file. You can now reduce your build cycle to an occassional .X BASIC.RUN
issued from the editor. Even if your program is not suitable for running from the editor (because, for instance, it is a subroutine not designed to be run independently), you can still save and compile it in this way: create an alternative macro called just BASIC
which omits the RUN
command.
Note once again the use of @FILE
and @ID
to replace BP
and HELLO.WORLD
: these tokens automatically take the appropriate values for the record your are editing, and allow you to use the same macro while editing any program. Again, all this is explained in the section Editor Macros.
You may wish to create a VOC record to run your program: allowing you, and your client users, to run your program by entering a single command at the UniVerse prompt. The simplest way is by creating a paragraph:
>ED VOC RUN.HELLO.WORLD
New record.
----: I
0001= PA Say hello to the world
0002= RUN BP HELLO.WORLD
0003= (Press RETURN)
Bottom at line 2.
----: FI
"RUN.HELLO.WORLD" filed in file "VOC".
>
This will work perfectly well. However, it is probably better to create a verb rather than a paragraph, like this:
>ED VOC HELLO.WORLD
New record.
----: I
0001= V Say hello to the world
0002= HELLO.WORLD
0003= B
0004= BP.O
0005= (Press RETURN)
Bottom at line 4.
----: FI
"HELLO.WORLD" filed in file "VOC".
>
The B
on the third line indicates the HELLO.WORLD
is a Basic program, and the BP.O
on the fourth provides the name of the file which stores the programs object code.
Both paragraphs and verbs were covered in greater depth earlier in this course. See Paragraphs and Verbs for more information.
So why prefer the verb to the paragraph? Chiefly because it is specfically designed for this job. A paragraph is a device for handling command scripts of all kinds: a verb is purpose build for running programs, and so a more precise fit to the purpose.
Also, there is a system variable called @SENTENCE
which you can use in a UniVerse Basic to capture the string that the user typed in to run your program, and which is usually used to support command line parameters. The @SENTENCE
value generated by the paragraph includes the words RUN BP
, which are just noise and make the command string harder to parse.