.MH "Program Development" .bq .pp One of the most important uses of the Software Tools Subsystem is program development. The Ratfor language presented in [ul Software Tools] is an elegant language for software developers, and is the foundation of the Subsystem; virtually all of the Subsystem is written in Ratfor. .eq .# .# .SH "Developing Programs" To acquaint you with the several steps of program development, we present an example in which we develop a simple Ratfor program. We use a Ratfor example here because Ratfor is the most widely used language in the Subsystem --- but for a few lines here and there, the entire Subsystem is written in Ratfor. If you want to learn more about Ratfor programming, you can read the .bf .ul User's Guide for the Ratfor Preprocessor. .sb Meanwhile, on with the example . . . . .xb .# .# .SH "The Subsystem Text Editor" .# .# The first program most users will see when they wish to create another program is 'ed', the Subsystem text editor, or if you have a crt, 'se', the screen editor. A complete description of either is beyond the scope of this tutorial, but a short list of commands (accepted by both the line editor and full screen editor) and their formats, as well as an example using 'ed,' should help you get started. For more information refer to .ul Introduction to the Software Tools Text Editor and of course to .ul Software Tools. .pp 'Ed' is an interactive program used for the creation and modification of "text". "Text" may be any collection of characters, such as a report, a program, or data to be used by a program. All editing takes place in a "buffer", which is nothing more than 'ed's own private storage area where it can manipulate your text. 'Ed's commands have the general format .be , .ee where, typically, both line numbers are optional. Commands are one letter, sometimes with optional parameters. .pp The symbol above can have several formats. .ne 4 Among them are: .bq .ta 4 .HI 3 [bf .] an integer, meaning the line with that number. For example, if the integer is 7, then the 7th line in the buffer; .HI 3 [bf .] a period ("."), meaning the current line; .HI 3 [bf .] a dollar sign ("$"), meaning the last line of the buffer; .HI 3 [bf .] /string/, meaning the next line containing "string"; .HI 3 [bf .] .tc \string\, meaning the previous line containing "string"; .tc \ .HI 3 [bf .] any of the above expression elements followed by "+" or "-" and another expression element. .eq .pp All commands assume certain default values for their line numbers. In the list below, the defaults are in parentheses. .sp .in +25 .ta 21 .ti -20 .ul Command\Action .HI 20 (.)a Appends text from standard input to the buffer after the line specified. The append operation is terminated by a line containing only a period in column 1. Until that time, though, everything you type goes into the buffer. .HI 20 (.,.)d Deletes lines from the first line specified to the last line specified. .HI 20 "e filename" Fills the buffer from the named file. [cc]mc | Anything previously in the buffer is lost. [cc]mc .HI 20 (.,.)p Prints lines from the first line specified to the last. 1,$p prints the entire buffer. .HI 20 q Causes 'ed' to return to the command interpreter. Note that unless you have given a "w" command (see below), everything you have done to the buffer is lost. .HI 20 "(.)r filename" Reads the contents of the named file into the buffer after the specified line. .HI 20 (.,.)s/old/new/p Substitutes the string "new" for the string "old". If the trailing p is included, the result is printed, otherwise 'ed' stays quiet. .HI 20 "(1,$)w filename" Writes the buffer to the named file. This command must be used if you want to save what you have done to the buffer. .HI 20 ? Prints a longer description of the last error that occurred. .in -25 .pp If 'ed' is called with a filename as an argument, it automatically performs an "e" command for the user. .pp 'Ed' is extremely quiet. The only diagnostic message issued (except in a time of dire distress) is a question mark. Almost always it is obvious to the user what is wrong when 'ed' complains. However, a longer description of the problem can be had by typing "?" as the next command after the error occurs. The only commands for which 'ed' provides unsolicited information are the "e", "r", and "w" commands. For each of these, the number of lines transferred between the file and 'ed's buffer is printed. .pp You should note that specifying a line number without a command is identical to specifying the line number followed by a "p" command; i.e., print that line. .# .# .SH "Creating a Program" .# .# Now that we have a basic knowledge of the editor, we should be able to use it to write a short program. As usual, user input is boldfaced. .be 20 [set 1 0] .ta 4 52 ] [bf ed]\([num +1]) [bf a]\\([num +1]) [bf # now --- print the current time]\([num +1]) [bf define(TIME_OF_DAY,2)]\([num +1]) \[bf character now (10)]\([num +1]) \[bf call date (TIME_OF_DAY, now)]\([num +1]) \[bf call print (STDOUT, "Now: *s*n"s, now]\([num +1]) \[bf stop]\([num +1]) \[bf end]\([num +1]) [bf .]\\([num +1]) [bf w now.r]\([num +1]) 11\\([num +1]) [bf q]\\([num +1]) ]\\([num +1]) .fi [set 1 0] .ta 6 .HI 5 ([num +1]) You invoke the editor by typing "ed" after the command interpreter's prompt. 'Ed,' in its usual soft-spoken manner, says nothing. .HI 5 ([num +1]) 'Ed's "a" command allows text to be added to the buffer. .HI 5 ([num +1]) Now you type in the text of the program. The sharp sign "#" introduces comments in Ratfor. .HI 5 ([num +1]) Ratfor's built-in macro processor is used to define a macro with the name "TIME_OF_DAY". Whenever this name appears in the program, it will be replaced by the text appearing after the comma in its definition. This technique is used to improve readability and allow quick conversions in the future. .HI 5 ([num +1]) An array "now", of type character, length 10, is declared. .HI 5 ([num +1]) The library routine 'date' is called to determine the current time. .HI 5 ([num +1]) The library routine 'print' is called to perform formatted output to the program's standard output port. .HI 5 ([num +1]) The "stop" statement causes a return to the Subsystem command interpreter when executed. .HI 5 ([num +1]) The "end" statement marks the end of the program. .HI 5 ([num +1]) The period alone on a line terminates the "a" command. Remember that this must be done before 'ed' will recognize any further commands. .HI 5 ([num +1]) With the "w" command, 'ed' copies its buffer into the file named "now.r". .HI 5 ([num +1]) 'Ed' responds by typing the number of lines written out. .HI 5 ([num +1]) The "q" command tells 'ed' to quit and return to the Subsystem's command interpreter. .HI 5 ([num +1]) The Subsystem command interpreter prompts with a right bracket, awaiting a new command. .ee .pp Now we are talking to the command interpreter again. We may now use the 'rp' command to change our program from Ratfor into Fortran, and hopefully compile and execute it. .be 3 [set 1 0] .ta 4 52 ] [bf rp now.r]\([num +1]) \8 (.main.): '' missing right parenthesis.\([num +1]) ]\\([num +1]) .fi [set 1 0] .ta 6 .HI 5 ([num +1]) 'Rp' is called. The argument "now.r" directs Ratfor to take its input from the file "now.r" and produce output on the file "now.f". .HI 5 ([num +1]) 'Rp' has detected an error in the Ratfor program. 'Rp's error messages are of the form .be line (program-element): 'context' explanation .ee In this case, a missing parenthesis was detected on line 8 in the main program. .HI 5 ([num +1]) 'Rp' has returned to the Subsystem's command interpreter, which prompts with "]". .ee .pp Looking back over the program, we quickly spot the difficulty and proceed to fix it with 'ed': .be 11 [set 1 0] .ta 4 52 ] [bf ed now.r]\([num +1]) 11\\([num +1]) [bf 8]\\([num +1]) \call print (STDOUT, "Now: *s*n"s, now\([num +1]) [bf s/, now/, now)/p]\([num +1]) \call print (STDOUT, "Now: *s*n"s, now)\([num +1]) [bf w]\\([num +1]) 11\\([num +1]) [bf q]\\([num +1]) ] [bf rp now.r]\([num +1]) ]\\([num +1]) .fi [set 1 0] .ta 6 .HI 5 ([num +1]) The editor is called as before. However, since we have given the name of a file, "now.r", to 'ed' as an argument, it automatically does an "e" command on that file, bringing it into the buffer. .HI 5 ([num +1]) 'Ed' types the number of lines in the file. .HI 5 ([num +1]) We type the line number 8, since that is the line that 'rp' told us had the error. .HI 5 ([num +1]) 'Ed' responds by typing the line. (Remember that a line number by itself is the same as a "p" command of that line number.) .HI 5 ([num +1]) We use 'ed's "s" command to add the missing parenthesis. Note the use of the "p" at the end of the command. .HI 5 ([num +1]) 'Ed' makes the substitution, and since we have specified the "p", the result is printed. .HI 5 ([num +1]) We now write the changed buffer back out to our file ('ed' remembers the file name "now.r" for us). .HI 5 ([num +1]) 'Ed' prints the number of lines written. .HI 5 ([num +1]) We exit from the editor with the quit command "q". .HI 5 ([num +1]) We invoke Ratfor to process the program. Ratfor detects no errors. The output of the preprocessing is on file "now.f". .HI 5 ([num +1]) The command interpreter prompts us for another command. .ee .pp Now that the Ratfor program has been successfully preprocessed, it is time to compile the Fortran output, which was placed in the file "now.f". 'Fc,' should be used to compile Subsystem programs, since it selects several useful compiler options and standardizes the compilation process: .be 5 ] [bf fc now.f] 0000 ERRORS [<.MAIN.>FTN-REV18.4] ] .ee .pp All of the garbage between the "fc" and the "]" prompt is stuff produced by the Fortran compiler and is mostly irrelevant at this point. The essential thing to recognize about it is that the number before "ERRORS" is zero. .pp Now that our program has compiled successfully, we bravely proceed to invoke the Linking Loader using 'ld.' 'Fc' has left the output of Fortran in the file "now.b". We will use 'ld's "-o" option to select the name of the executable file: .be 22 ] [bf ld now.b -o now] [cc]mc | [SEG rev 19.2.GT] [cc]mc # vl # $ co ab 4001 $ sy swt$cm 4040 40000 $ sy swt$tp 2030 120000 $ mi $ s/lo now.b 0 4000 4000 $ s/lo 'lib>vswtlb' 0 4000 4000 $ s/li 0 4000 4000 [cc]mc | LOAD COMPLETE $ ma 6 [cc]mc $ re # sh TWO CHARACTER FILE ID: .. # delete # q ] .ee .nh .pp Again, all the noise between "ld" and "]" comes from the Loader. The important thing to notice here is the "LOAD[bl]COMPLETE" message, which indicates that linking is complete. If we did not get the "LOAD[bl]COMPLETE" message, we would re-link using the command "ld -u now.b -o now" and the loader would then list the undefined subprograms. .hy .pp We now have an executable program in our directory. We can check this using 'lf': .be ] [bf lf] now now.b now.f now.r ] .ee .pp Deciding we do not need the Fortran source file and the intermediate binary file hanging around, we remove them with 'del': .be 3 ] [bf del now.f now.b] ] [bf lf] now now.r ] .ee And getting really brave, we try to run our newly created program: .be ] [bf now] Now: 16:34:41 ] .ee .pp Hopefully the preceding example will be of some help in the development of your own (more important) programs. Even though it is simple, it shows almost all the common steps involved in creating and running a typical program. .# .# .SH "Caveats for Subsystem Programmers" .# .# Since the Subsystem is exactly that, not an operating system but a sub-system, programs written for it must follow a few simple conventions, summarized below. .bq .ta 4 .HI 3 [bf .] To exit, a program running under the Subsystem should either use a "stop" statement (Ratfor programs only), "return" from the main program (Pascal and PL/I[bl]G), or call the subroutine "swt". Specifically, the Primos routine "exit" must [ul not] be .nh called .hy to terminate a program. .HI 3 [bf .] Whenever possible, Subsystem i/o and utility routines should be used instead of Primos routines, since the latter cannot handle all aspects of the Subsystem files. If, however, programs must use native i/o routines, remember that they must inform their native i/o routines of the Subsystem by calling the proper initialization routines (see Subsystem Interface Subroutines in the table below), or they will not be able to take advantage of standard input, standard output or any of the other i/o related features provided by the Subsystem. .eq .ne 30 .pp The Subsystem interfaces available for Primos languages and utilities are summarized below: .nf .be 42 .bf 4 .ta 15 28 41 54 Language\Primos\Primos\Subsystem or\Subsystem\Commands\Interface .ul Utility\Interface\Interfaced\Subroutines [cc]mc | C\xcc\CC\ - \xccl\CC, SEG [cc]mc Cobol\cobc\COBOL\ - \cobcl\COBOL, SEG\ Database\fsubc\FSUBS\ - \fdmlc\FDML \fdmlcl\FDML, FTN, \\SEG \csubc\CSUBS\ - \cdmlc\CDML \cdmlcl\CDML, \\COBOL, \\SEG \ddlc\SCHEMA\ - Debugger\dbg\DBG\ - \vpsd\SEG Fortran 66\fc\FTN\init$f, \fcl\FTN, SEG\geta$f Fortran 77\f77c\F77\init$f, \f77cl\F77, SEG\geta$f Loader\ld\SEG\ - Pascal\pc\PASCAL\init$p, \pcl\PASCAL, SEG\file$p, \\\geta$p PL/P\plpc\PLP\ - \plpcl\PLP, SEG PL/1 G\plgc\PL1G\init$plg, \plgcl\PL1G, SEG\geta$plg Prime\pmac\PMA\ - Assembler\pmacl\PMA, SEG SPL\splc\SPL\ - \splcl\SPL, SEG .ee .pp Use 'help' or refer to the Subsystem Reference Manual for a complete description of Primos/Subsystem interface commands and Subsystem interface subroutines.