Mercurial > hg > Members > kono > nitros9-code
changeset 24:01a6e267aa38
Added the Basic09 Reference Manual
author | roug |
---|---|
date | Sat, 06 Apr 2002 13:34:58 +0000 |
parents | dac1f4e899fe |
children | ad78331ace28 |
files | docs/basic09/basic09.docbook docs/basic09/makefile |
diffstat | 2 files changed, 7734 insertions(+), 0 deletions(-) [+] |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/basic09/basic09.docbook Sat Apr 06 13:34:58 2002 +0000 @@ -0,0 +1,7715 @@ +<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook V4.1//EN" [ + <!ENTITY b09 "BASIC09"> + <!ENTITY minus "-"> +]> +<book id="basic09" lang="en"> + <bookinfo> +<title>&b09;</title> +<subtitle>Programming Language Reference Manual</subtitle> +<titleabbrev>&b09; Reference Manual</titleabbrev> + +<copyright> +<year>1983</year> +<holder>Dragon Data Ltd. and Microware Systems Corporation. +All Rights Reserved. +Basic 09 is a trademark of Microware Systems Corporation and Motorola Inc. +</holder> + +</copyright> +<revhistory> +<revision> +<revnumber>F</revnumber> +<date>February 1983</date> +</revision> +</revhistory> +</bookinfo> + + + +<chapter> +<title>Introduction</title> +<subtitle>Introduction to &b09; Programming</subtitle> +<sect1> +<title>Comments on &b09;</title> +<para> +&b09; is an enhanced structured Basic language programming +system specially created for the 6809 Advanced Microprocessor +used by the Dragon Computer. +In addition to the standard BASIC language statements and functions, +&b09; includes many of the useful elements of the PASCAL +programming language so that programs can be modular, +well-structured, and use sophisticated data structures. +It also permits full access +to almost all of the OS-9 Operating System commands and functions so it +can be used as a systems programming language. +These features make &b09; an ideal language for many applications: +scientific, business, industrial control, education and more. +</para> +<para> +&b09; is unusual in that it is an <emphasis>Interactive Compiler</emphasis> that +has the best of both kinds of language system: it gives +the fast execution speed typical of compiler languages plus the ease of use +and memory space efficiency typical of interpreter languages. +&b09; is a complete PROGRAMMING SYSTEM that +includes a powerful text editor, multi-pass compiler, +run-time interpreter, high-level interactive debugger, and a system +executive. Each of these components was carefully integrated +to give the user a +friendly, highly interactive programming resource. that provides all the tools +and helpful "extra" facilities needed for fast, accurate creation and testing of +structured programs. +</para> + +<highlights> +<para> +&b09; Features + +<itemizedlist mark="bullet"> + +<listitem> + <para> + Structured, recursive BASIC with Pascal-type enhancements: + <itemizedlist mark="dash"> + <listitem><para>allows multiple, independent, named procedures</para></listitem> + <listitem><para>procedures called by name with parameters</para></listitem> + <listitem><para>multi-character, upper or lower case identifiers</para></listitem> + <listitem><para>variables and line numbers local to procedures</para></listitem> + <listitem><para>line numbers optional</para></listitem> + <listitem><para>automatic linkage to ROM or RAM "library" procedures</para></listitem> + <listitem><para>PACK command compacts program and provides security</para></listitem> + <listitem><para>PRINT USING with FORTRAN-like format specifications</para></listitem> + </itemizedlist> + </para> +</listitem> + + +<listitem> +<para> +Extended data structures: + <itemizedlist mark="dash"> + <listitem><para>Five Basic data types: BYTE, INTEGER, REAL, BOOLEAN, and STRING</para></listitem> + <listitem><para>One, two, or three dimensional arrays</para></listitem> + <listitem><para>User-defined complex structures and data types</para></listitem> + </itemizedlist> +</para> +</listitem> + + +<listitem> +<para> +Extended Control Structures (with Unique Closure Elements): +</para> +</listitem> + + +<listitem> +<para> +Graphics Interface Module for Access to Dragon Computer Colour +Graphics Functions +</para> +</listitem> + + +<listitem> +<para> +Powerful interactive debugging and editing features: + <itemizedlist mark="dash"> + <listitem><para>Integral, full-featured text editor</para></listitem> + <listitem><para>Syntax error check upon line entry and procedure compile</para></listitem> + <listitem><para>Trace mode reproduces original source statements</para></listitem> + <listitem><para>Renumber command for line numbered procedures</para></listitem> + </itemizedlist> +</para> +</listitem> + + +<listitem> +<para> +High-speed, high-accuracy math: + <itemizedlist mark="dash"> + <listitem><para>9 decimal-digit 40 bit binary floating point</para></listitem> + <listitem><para>Full set of transcendentals (SIN, ASN, ACS, LOG, etc.)</para></listitem> + </itemizedlist> +</para> +</listitem> +</itemizedlist> + +</para> +</highlights> +</sect1> +<sect1> +<title>The History of &b09;</title> +<para> +&b09; was conceived in 1978 as a high-performance +programming language to demonstrate the capabilities of the 6809 +microprocessor to efficiently run high-level languages. &b09; +was developed at the same time as the 6809 under the auspices of the +architects of the 6809. The project covered +almost two years, and incorporated the results of research in such areas as +interactive compilation, fast floating point arithmetic algorithms, storage +management, high-level symbolic debugging, and structured language +design. These innovations give &b09; its speed, power, and +unique flavor. +</para><para> +&b09; was commissioned by Motorola, Inc., Austin, Texas, +and developed by Microware Systems Corporation, Des Moines, Iowa. +Principal designers of &b09; were Larry Crane, Robert +Doggett, Ken Kaplan, and Terry Ritter. The first release was in February, +1980. +</para><para> +Excellent feedback, thoughtful suggestions, and carefully documented bug +reports from &b09; users all over the world have been +invaluable to the designers in their efforts to achieve the degree of +sophistication and reliability &b09; has today. +</para> +</sect1> +</chapter> + + + +<chapter> +<title>Introduction to &b09; Programming</title> +<para> + +This section is intended for persons who have not previously +written computer programs. If you are familiar with programming in +general or BASIC programming specifically, this section can give you +a "feel" for the &b09; interactive environment. + +</para> +<sect1><title>What is a Program?</title> +<para> +A computer works something like a pocket calulator. With a +calculator you push a button, some calculation occurs, and the +result is displayed. On some calculators you can write a program +which is just a list of the buttons you want pushed, in the order +you want them pushed. This is very similar to a computer program, +but most computer languages use command names instead of buttons. +</para> + +<para> +To get results from a computer, you must first put into the +computer the list of commands you want executed in the order you +want them executed. Each command will mean "do this thing" or "do +that thing", but the computer only has certain commands which it +will understand. A computer can do things like "add" or "save the +result into memory". Typing "get me a taco" to a computer won't +get it; similarly, on a calculator you can't push buttons which +aren't there. After you have stored a list of commands into the +computer, you can tell it to perform those operations. This is like +actually pushing the buttons on a hand calculator. Then, if you +remembered to have the compuer display your results, you get to see +them. Generaly, a computer does not automatically display results +like a hand calculator. More calculations occur in a computer then +in a calculator, and displaying all these results would simply be +overwhelming. +</para> + +<para> +You enter a program into a computer by using the computer +itself as a "text editor", to store the commands you type in. Some +editors allow you to enter any text you want. Other editors will +only store valid computer commands. Even if the computer does store +all the text you type in, it can only execute those commands it +knows. If during program execution, &b09; finds a word which does +not correspond to a command it will probably stop and print out an +"error message". Other editors check each command as you enter it +(usually after the carriage-return ending each line) and print error +messages immediately for invalid commands. After typing in your +list of commands, there are ways to display that list, to modify the +commands you have typed in, and to insert others. But simpy +entering a computer program does not get results any more than +thinking which buttons to push will get results on a calculator. +You store your program by typing it into a computer, but no results +are available until after you start the program running. +</para> +<para> +Even though programming is conceptually simple, it is easy to +misspell commands which &b09; will not interpret correctly. +Unlike humans, &b09; does not infer anything: Every command must +be perfectly spelled and punctuated or it is wrong. Even after +spelling errors are eliminated, it is likely that the sequence of +commands you have entered will not do the job you wanted it to do. +The meaning of the program to &b09; is often quite different than +was intended by the programmer, biut good intentions just don't push +the right buttons. After you get the program to run without obvious +error, you must test the program with sample input and see that it +produces results which are known correct. If the results are incorrect, +the program must be modified and tested until it does +produce correct results. This is known as testing and +debugging. Computer malfunctions are rare, and if the computer +works to store the program, it is probably working perfectly. If the +program does not work, you need to puzzle out how the computer is +doing something hich you didn't realize that you told it to do. +Programming can be frustrating, but if you enter the right commands, +the computer will do the right things for you. +</para></sect1> +<sect1><title>A Simple &b09; Program</title> +<para> +Probably the easiest way to explain programming is by example. +This simple program sometimes keeps kids happy for hours. First, +the program asks the user for his name. Then the computer types out +"Hi", then the name, then "see you later". This may not seem like +much, but it is great fun to type in things which are not your name, +and see if they will be printed out. They will, of course. +</para> +<para> +When you turn on the &b09; computer it will print some heading +information. If the prompt is "OS9: ", enter the "basic09" (and +a carriage-return) to get to the prompt "B:". When you have the +prompt "B:", it means that the system is in the &b09; "command +mode". While in the command mode, you can do several things, like: +list, kill, or create programs (called "procedures" in &b09;). +&b09; lets you keep several different programs in memory at the +same time. Each procedure is identified by a name you give it when +you create the procedure.</para> +<para> +To create a new procedure you command the system to enter the +"edit mode" by typing a simpl "e" (in upper or lower case) and a +carriage-return (the ENTER or RETURN key). The Editor lets you +enter or change programs and actually checks for many common errors +as you type in your program. This automatic checking feature is one +of the nicest things about &b09;. Because it's always "looking +over your shoulder" to catch mistakes, it saves a lot of debugging +time! If you're not 100% sure about how something works - you can +go ahead and try it instead of digging through this manual. If you +guess wrong &b09; will usually show you where and why. +</para> +<para> +Because you did not specify a particular procedure name, +&b09; will automatically select the name "PROGRAM" for you, and +will respond by printing out "PROCEDURE PROGRAM"; this means that +you will be editing a procedure which is named PROGRAM. Later you +will see that you can enter many different procedures and give them +different names (just type the name you want to use for the program +after the "e"). +</para> +<para> +The computer output so far is a follows: +<programlisting> +B:e +PROCEDURE PROGRAM +* +E: +</programlisting> +The asterisk (*) indicates the "current edit line" in the procedure +being edited. In this case the current line is empty since you have +not yet entered anything. The asterisk is handy, since you will be +moving back and forth between different lines to edit them. Later +you will be "opening" existing procedures for modification, and the +first line will be displayed automatically, helping identify that +you are editing the correct program. +</para> +<para> +When &b09; responds with the edit prompt "E:", it is in the +edit mode. Now you can enter "edit commands" which help us enter +the computer program. While in edit mode, &b09; ALWAYS TAKES THE +FIRST CHARACTER OF EVERY LINE AS AN EDIT COMMAND. Some of the basic +edit commands are: +<programlisting> +<space> <program statement> <cr> insert line +? <cr> go to next line down (just <cr> also does the same) +- <cr> move back to previous line +L <cr> list current line +d <cr> delete current line +</programlisting> +The most-important edit command is the (invisible) space character; +this means "save the following line of text", The "space" command +is the way most text is entered into the system. you must type an +edit command at the start of each line. If a line is to be entered, +you must type a space before the rest of the line. If you forget to +type an edit command, &b09; will respond with "WHAT?". Another +useful edit command is "L*" (or "l*", since the editor accepts +either upper or lower case) which will display the whole procedure. +This allows you to watch the procedure develop as lines are entered. +</para> +<para> +You use the "space" command to enter the following line: +<programlisting> +E: print "type your name" +* +</programlisting> +When &b09; executes procedure PROGRAM, this line will tell it to +print on the screen all of the characters between the quotes. +</para> +<para> +As mentioned before, &b09; checks for errors at the end of +each line and again when the edit is finished. These errors are, in +general, anything &b09; cannot identify or things that don't +conform to the rules of the language. An error could be a bad +character, mismatched parenthesis, or one of many other things. +&b09; will print out an "error code" to identify the error and +print an up arrow character under the place in the line where it +detected the error. The error codes are listed at the end of this +manual. If the error was detected at the end of the edit session, +the I-code location of the error will also be printed. This cryptic +information is all &b09; knows about the problem, hopefully, it +will help you to find and fix the error. +</para> +<para> +In the same way that you entered the first line, enter the +following lines. Remember that the first character entered must be +a space to get &b09; to save the rest of the line. Example: +<programlisting> +E: input name$ +* +E: print "Hi ";name$;", see you later." +* +E: end +* +</programlisting> +The second line ("input name$"), when executed, commands &b09; to +wait for a line of text to come in from the keyboard (this will +happen after the user reads the message printed out in the first +line). &b09; will accumulate text from the keyboard character-by-character +until a carriage-return ends the line. This text is +placed in memory corresponding to the variable "name$". The dollar-sign +($) on the end of the variable tells &b09; that you want to +store a sequence of characters as opposed to a number. +</para> +<para> +The third line of procedure PROGRAM (print "Hi ";name$;", see +you later."), starts out like the first line. The command "print" +causes &b09; to print out the various values which come after it. +When this line is executed, the characters H, i, and "space" are +printed out since the are enclosed in double-quotes. Next, without +additional spaces, &b09; prints out the line which was typed in by +the user and saved in the memory corresponding to "name$" and prints +out " see you later". When a PRINT statement contains multiple values, +it will print them out one after the other. If the separator +is a comma, &b09; will move to the next 16-column "tab stop" +before printing the next value. However, if the separator between +print values is a semicolon, absolutely no space will separate the +values. The last line of the procedure ("END") tells &b09; to +stop executing the program and return to the command mode (B:). +You have not yet EXECUTED the procedure, you are just EDITING. If +you type in l* the whole program will be listed, as follows: +<programlisting> +E:l* +PROCEDURE PROGRAM + 0000 PRINT "type your name" + 0012 INPUT name$ + 0017 PRINT "Hi ";name$;", see you later." + 0035 END +* +E: +</programlisting> +Notice that the editor has added some information which you did not +type in. You can use this listing to show exactly what to type in +to run this program, but the editor only wants the relevant +information. +</para> +<para> +The numbers to the left are "I-code addresses". These are the +actual memory locations relative to the start of the procedure where +each line begins. These numbers may look strange because they are in +hexadecimal (base 16). These values are important, since the +compiler may find errors at some I-code location and will try to +convey that information it has to the programmer. I-code addresses +are supplied automatically by &b09;. +</para> +<para> +The space between the "I-code addresses" and the beginning of +the program line is reserved for "line numbers". Line numbers are +required in many versions of BASIC (although not in &b09;). +Notice that although the program was typed in lower case some words +are printed in upper case. &b09; identifies valid command +"keywords" and converts them to upper case automatically. +</para> +<para> +Now let's run it. First type "q" to quit the editor. We are +nowback in "command mode" ( B:). Now type "run". &b09; +remembers the procedure edited (PROGRAM) and starts to execute +it. +<screen> +E:q +READY +B:run +type your name +? tex +Hi tex, see you later. +READY +B: +</screen> +The question mark (?) is the normal input prompt to tell the user +that the program is waiting for input. +</para> +<para> +This program is extremely simple, but younger kids can get +grat fun from it. Its action is especially amusing to young people +who are learning a computer language for the first time because a +machine is "responding" to them, and because the machine is too +easily "fooled" if you do not type in a real name. +</para></sect1> +<sect1><title>Basic Programming Techniques: Loops and Arithmetic</title> +<para> +Another simple program that most of us can identify with is a +program to print out multiplication tables. +<programlisting> +PROCEDURE multable + FOR i=1 TO 9 + FOR j=1 TO 9 + PRINT i*j; TAB(5*j); + NEXT j + NEXT i +</programlisting> +First, open the editor by typing "e multable", as follows: +<screen> +B: e multable +PROCEDURE multable +* +E: +</screen> +Next, type in the program line-by-line staring with "FOR i=1 TO 9" +(lower-case is perfectly fine). If you loose your way, type "L*" to +see where you are. This will display the entire procedure and put +an asterisk at the left of the current line. If you make a mistake, +use "+" or "-" to mode to that line, use "d" to delete the line, and +use the space command to enter the line over. Make sure that there +are no errors and then type "q". When you have the program running, +try adding a statement before "FOR i=1 TO 9" as follows: "DIM +i,j:INTEGER". +</para> +<para> +The FOR i=1 TO 9 and NEXT i constitute the start and end of a +control structure or "loop". A control structure is used to cause +repeated or conditional execution of the statement(s) it surrounds. +A control structure usually has one entry at the top and one exit at +the bottom. In this way, the entire structure take on the properties +of a single statement. The beginning statement of the +FOR...NEXT structure (FOR...) provides a "loop initialization", places +the value 1 in the storage called "i", and sets up the operation of +the following NEXT (every FOR must have a NEXT). When "NEXT i" is +executed, the value in "i" is increased by 1 (which is the default +STEP size) and compared to the value 9 (which is the ending value +for this loop). If the resulting "i" is less than or equal to 9, +the statement(s) following that FOR... is (are) executed. +</para> +<para> +Loops can be "nested" to execute the enclosed statements even +more times. For example, the PRINT statement in "multable" is +executed 81 times; once for each of 9 values of "j" and this number +(9 times) for each of 9 values of "i". The ability to tremendously +increase the number of times some code is executed is at the heart +of both computer programming and computer errors. It means that +a vary small portion of a program can often be made to do the vast +majority of the work. But a few remaining special cases may require +individual handling and may consume more programming and code than +that which "usually" works. Unfortunately, "usually" is not +sufficient. A special case which occurs once in a thousand times +may occur once a second, and if the error stops the program, further +processing of normal values also stops. Experience has indicated +that the programmer should know what is happening in the first and +second pass, and the next-to-the-last and last pass through each +loop in the program. +</para></sect1> +<sect1><title>Listing Procedure Names</title> +<para> +The "DIR" command causes &b09; to display the names and sizes +of all procedures in memory. This command is used so frequently +that there is a quick shorthand for DIR: a simple <cr> when in +command mode does the same thing. You will see +a table of all procedure names and two numbers next to each +name. The first column, "proc size", is the size of the corresponding +procedure. The "data size" column shows the amount of memory that the +procedure requires for its variables. +On the last line this command shows the amount of free bytes of workspace memory +remaining. You can use this information to estimate how much memory +your program needs to run. You must have at least as much free memory as +the <emphasis>data size</emphasis> of the procedure(s) to be run. If a data size number is +followed by a question mark, you need more memory. +</para> +</sect1> +<sect1> +<title>Requesting More Memory</title> +<para> +&b09; automatically get 4K of workspace memory from +OS-9 when it starts up. There is almost always more than this +available, but &b09; does not grab it all so other tasks running +on your computer can have memory too. If you are not multitasking +and need more memory, the MEM command can get it if available. +Just type MEM and the amount of memory you want. Depending on your +computer and how it is configured, you can usually get at least 24K +in OS-9 Level One Systems or 40K in OS-9 Level Two systems. For +example: +<programlisting> +MEM 20000 +</programlisting> + +requests 20.000 (20K) bytes of memory. &b09; will always round the +amount you request up to the next highest multiple of 256 bytes. If MEM +responds with "WHAT?", this means that much memory is not +available. There is another convenient way to do the same thing +when you first call up &b09; from OS-9. OS-9 has a +"#" <emphasis>memory size option</emphasis> on command lines +that let you specify how much memory to give the program. +To call &b09; with 16K of memory to start with, you can type: +<programlisting> +OS9: basic #16k +</programlisting> +</para> +</sect1> +<sect1> +<title>Storing and Recalling Programs</title> +<para> +Nobody wants to retype a whole program every time it is to be +run. Two commands, SAVE and LOAD, are used to store programs and +recall previously "SAVEd" programs to or from OS-9 disk files. The +simples way to use SAVE is by itself. It will store the procedure +last edited or run on a disk file having the same name. For +example: +<programlisting> +B: save +</programlisting> +If our procedure name was the default name "PROGRAM", &b09; will +create a file called "PROGRAM" to hold it. OS-9 won't let you have +two files of the same name because unique names are necesary to +identify the specific file you want. Therefore if a file called +"PROGRAM" already exists, &b09; will ask you: +<screen> +Overwrite? +</screen> +If you respond "Y" for YES, it will replace the file previously +stored on that file with the program to be saved. This is OK if +what you want to save is a never version of the same program. But if +not you will permanently erase another program you may have wanted +to keep. If this is the case answer "N" for NO. Fortunately, there +is a simple way to store the procedure on a file using a different +name: just type SAVE, a ">", and a different file name of your +choice. The file can consist of any combination of up to +thirty-one letters, numbers, periods, or underscores ("_"). The only +restriction is that the name must start with a letter A-Z or a-z. +For example: +<programlisting> +save >newprogram5 +</programlisting> +will save the program on a file called "newprogram5". There are +several useful variations of the SAVE command that let you save +various combinations of programs on the same file. See the SAVE +command description for more information. You should also read +Chapter 2 of the "OS-9 Users Manual" to learn about the OS-9 +commands that deal with disk files. +</para> +<para> +If you exit from &b09;, it will not automatically save your +programs. You must make sure to save them before you quit, or they +will be lost unless the were saved at some time before! +</para> +<para> +The LOAD command, as it's name implies, reads in a previously +save program from a file. You must give the name of the file with +the command. For example: +<informalexample> +<programlisting> +load program +</programlisting> +</informalexample> +If you just started &b09; and have not created any procedures, +the command is very straightforward. As the procedure(s) stored in +the file are loaded, &b09; displays their name(s) as they are +brought in. Once the program is loaded, you can edit and/or run +it. But if you have a procedure in &b09; that has the same name +as a procedure stored in the file, &b09; will replace it with the +new version loaded from the file. If this kind of conflict exists +you could loose your old program, so be sure to save or RENAME it +before loading a new one (remember that &b09; can keep several +procedures in memory at the same time as long as they have different +names). If you want to permanently erase all other procedures +before loading new ones, you can type: +<programlisting> +B: kill* +</programlisting> +This tells &b09; to "kill" all procedures in memory and has the +same effect as completely resetting &b09;. +</para> +</sect1> +<sect1> +<title>How to Print Program Listings</title> +<para> +If your computer is equipped with a printer, you will want to +make hard-copy listings of your programs. This is easy to do - just +type: +<programlisting> +B: LIST* /p +</programlisting> +This tells &b09; to LIST all procedures in memory to the output +device "/p" which is the printer device name in most OS-9 systems. +Like the SAVE command, LIST has several useful variations. If you +want to list just one procedure (if there are more than on in +memory) you can type: +<programlisting> +B: LIST procedurename >/P +</programlisting> +If you want, you can put two or more procedure names (seperated by +spaces) before the semicolon and those specific procedures will be +listed. +</para> +<para> +Notice that if you omit the "/p" or ">/p" from the commands above, +the programs will be listed on your display instead of the printer. +This is the same as the "L*" command in Edit Mode. You will also +notice that the listing will be automatically "pretty-printed", +e.g. program levels within loops are indented for easy reading. +</para></sect1> +<sect1><title>&b09;'s Four Modes:</title> +<para> +At any given time, &b09; is in one of four modes: + +<literallayout> +SYSTEM MODE: Used for executing system commands. +EDIT MODE: Used for creating/editing procedures. +EXECUTION MODE: Used for running procedures. +DEBUG MODE: Used for testing procedures for errors. +</literallayout> +So far, you have been exposed to System Mode (SAVE, LOAD, etc.), +Edit Mode (the editor), and Execution Mode (RUN). A section of this +manual is devoted to each mode. The chart below shows how various +commands in each mode causes changes to other modes. + +<figure> +<title>&b09; Mode Change Possibilities</title> +<screen> + OS-9 SYSTEM MODE EDIT MODE +---------- ------------ ------------ +| | | | | + | +| | | $ | | - | +| | <-----+--<eof> | | <cr> | +| | <-----+--BYE | | <line#> | +| | | CHD | | <space> | +| | | CHX | | c | +| | | DIR | | d | +| | | EDIT----+-------> | l | +| | | KILL | <-------+-q | +| | | LIST | | r | ------------ +|BASIC09-+-----> | LOAD | | s | | TRON | +| | | MEM | ------------ | TROFF | +| | | PACK | <--------------------------+ END or Q | +| | | RENAME | | DEG/RAD | +| | | RUN-----+-------> ------------ | STATE | +| | | SAVE | <-------+-END | | $ | +| | | | <-------+-<CTRL Q> | | BREAK | +| | ------------ <-------+-STOP | <-----+-CONT | +|BASIC09 | | PAUSE----+-----> | DIR | +|AUTORUN-+--------------------------> | ERROR----+-----> | LET | +| | | <CTRL C>-+-----> | LIST | +| | <--------------------------+-BYE | | PRINT | +| | | PROGRAM | <-----+-STEP | +---------- ------------ ------------ + EXECUTION MODE DEBUG MODE +</screen> +</figure> +</para> +</sect1> +<sect1><title>More about the Workspace...</title> +<para> +The workspace concept is important because &b09; and OS-9 are +both highly modular systems, and the workspace is a way to logically +group a set of procedures (i.e. modules) which are applicable to a +particular line of study or development. Modular software +development lets the programmer divide a large and complex project +into smaller, more manageable, and individually testable sections. +Modularity also lets programmers accumulate and use libraries of +commonly used routines. +</para> +<para> +As the software is written and debugged, &b09; makes it easy +to deal with the procedures that comprise an overall project, either +individually or as a group. For example, you can save all procedures +on the wrkspace to a single mass stoarage file or load a +file containing multiple procedures. Usually all procedures +associated witha project exists inside the workspace. However, you +can also call library procedures which are "outside" the workspace +in OS-9 memory module format. The library procedures can be written +in &b09; or machine language, can be in RAM or ROM memory, and can +even be shared by several users. +</para> +<para> +&b09; always reserves approximately 1.2K bytes of the workspace +for internal use. All remaining space is used for storage of +procedures and for procedure variable storage during execution. +&b09; will not run a procedure if there is not enough space for +variables. If you run out of workspace area, you can use the MEM +command to enlarge the workspace or you can kill procedures in the +workspace that are not needed. The "MEM" command can be used at any +time to change the size of the workspace. The size of the workspace +can be increased (subject to availability of free memory) or +decreased (but not below the minimal amount needed to store the +present workspace). +</para> +</sect1> +<sect1> +<title>Where to go From Here?</title> +<para> +A good way to learn &b09; is to use it! Try typing in and +running some of the example programs in the back of the book. Look +at and study the function of each program statement. Read the chapters +on the EDIT and DEBUG modes and experiment with more advanced +commands. Also, &b09; and the OS-9 Operating System are so intimately +connected, a basic understanding of OS-9 is important. See +Chapter 2 of the "OS-9 User's Manual". +</para> +</sect1> +</chapter> +<chapter> +<title>System Mode</title> +<para> +System mode includes commands to save, load, examine procedures; +commands to interact with OS-9; and other commands to +control the workspace environment. A complete list of system commands +is given below. +<table frame="none"> +<title>System Mode Commands</title> +<tgroup cols="5"> +<tbody> +<row> +<entry>$</entry> +<entry>CHX</entry> +<entry>EDIT</entry> +<entry>LOAD</entry> +<entry>RENAME</entry> +</row> +<row> +<entry>BYE</entry> +<entry>DIR</entry> +<entry>KILL</entry> +<entry>MEM</entry> +<entry>RUN</entry> +</row> +<row> +<entry>CHD</entry> +<entry>E</entry> +<entry>LIST</entry> +<entry>PACK</entry> +<entry>SAVE</entry> +</row> +</tbody> +</tgroup> +</table> +</para> +<para> +The system commands are processed by the &b09; "command interpreter" +which always identifies itself with the "B:" prompt. It is entered +automatically when &b09; is started up and +whenever you exit any other mode. Commands can be entered in either upper or +lower-case letters. +Commands such as DIR, MEM, "$", and BYE don't operate on specific +procedures, but may have optional or required parameters. Other commands +(such as SAVE, LOAD, PACK, KILL, and LIST) can operate on a specific +procedure or on ALL procedures within the workspace. +If the command is used with a specific procedure name, the command is +applied to only that procedure. For example: +<informalexample> +<programlisting> +list pete +</programlisting> +</informalexample> +will display the procedure named "pete". +The asterisk is a special name that means "all procedures in the +workspace". Therefore, if the command is given follwed by an asterisk it +is applied to all procedures. For example: +<programlisting> +list* +</programlisting> +will display all of the procedures in the workspace. +</para> +<para> +If the command is given without any name at all, the "current" working +procedure is used. This means the name of the procedure +last given in another command. The DIR command prints an asterisk +before its name so it can be found at any time. +If you have not yet given a name in any command, +the name "PROGRAM" is automatically used. Some commands that require a file +name as well as (one or +more) procedure names require that a ">" +precede the file name so it is not mistaken for a procedure name. If +you omit the file name, the name of the (first) procedure is used instead. +In this manual, the phrase file name means an OS-9 "pathlist" +which can describe either a file or device. +</para> +<para> +Here are some examples: +<programlisting> +SAVE tom bill >myfile +SAVE* big_file +</programlisting> +or +<programlisting> +SAVE tic tac toe +</programlisting> +which is exactly equivalent to +<programlisting> +SAVE tic,tac,toe >tic +</programlisting> + +Another class of commands use only one procedure name, or the +current working name if a name is omitted. These commands change +the mode of &b09; by exiting the command mode and entering another mode. +These commands are: +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="1in"> +<tbody> +<row> +<entry>RUN</entry> +<entry>which enters Execution Mode to run a procedure</entry> +</row> +<row> +<entry>EDIT</entry> +<entry>which enters Edit Mode to create or change a procedure</entry> +</row> +</tbody> +</tgroup> +</informaltable> +The one other mode, Debug Mode, cannot be entered directly from the +system mode — more on this later. +</para> +<bridgehead renderas="sect2"> +Syntax Notation Used in System Command Descriptions</bridgehead> +<para> +Individual descriptions of the available commands in each mode follow. In +order to precisely describe their formats, the syntax notation shown below +is used. + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="1.3in"> +<tbody> +<row> +<entry>[ ]</entry> +<entry>things in brackets are optional.</entry> +</row> +<row> +<entry>{ }</entry> +<entry>things in braces can be optionally repeated.</entry> +</row> +<row> +<entry><procname></entry> +<entry>means a procedure name</entry> +</row> +<row> +<entry><pathlist></entry> +<entry>An OS-9 file name</entry> +</row> +<row> +<entry><number></entry> +<entry>A decimal or hex number</entry> +</row> +</tbody> +</tgroup> +</informaltable> +</para> +<sect1> +<title>System Mode Commands</title> +<para> +<cmdsynopsis> +<command>$ [<text>] ("Shell" Command)</command> +</cmdsynopsis> +This command calls the OS-9 Shell command interpreter to process an OS-9 +command or to run another program. Running the OS-9 command does not +cause &b09; or its workspace to be disturbed. +</para> +<para> +If the "$" is followed by text, the Shell is called to process the +text as a single OS-9 command line. After the command is executed, +&b09; is immediately re-entered. +</para> +<para> +If no text is specified, &b09; is suspended, and the OS-9 Shell is called to +process multiple command lines individually entered from the keyboard. +Control is returned to &b09; when an end-of-file character (usually ESCAPE) is +entered. The contents of the &b09; workspace is not affected. This is a +convenient way to temporarily leave &b09; to manipulate files or perform +other housekeeping tasks. +</para> +<para> +This command is the "gateway" to OS-9 from inside &b09;. It allows access to +any OS-9 command or to other programs. It also permits creation of +concurrent processes and other real-time functions. +</para> +<para> +Examples: +<informalexample> +<literallayout> +B: $copy file1 file2 Calls the OS-9 copy command +B: $asm sourcefile& Calls the assembler as a <emphasis>background</emphasis> task +B: $basic09 fourier(20)& Starts <emphasis>another</emphasis> concurrent &b09; program +</literallayout> +</informalexample> +</para> +<cmdsynopsis><command>BYE (or ESCAPE character)</command> +</cmdsynopsis> +<para> +Exits &b09; and returns to OS-9 or the program that called &b09;. +Any procedures in the workspace are lost if not previously saved. The +escape key (technically speaking, an end-of-file character condition on +&b09;'s standard input path) does the same thing. +</para> +<cmdsynopsis><command>CHD <pathlist> or CHX <pathlist></command> +</cmdsynopsis> +<para> + +Changes the current OS-9 user Data +or Execution Directory to the specified pathlist +which must be a directory file. &b09; uses the Data Directory to LOAD or +SAVE procedures. The Execution Directory is used to +PACK or auto-load packed modules. +</para> +<para> +Example: +<informalexample> +<programlisting> +CHD /d1/joe/games +</programlisting> +</informalexample> + + +</para> +<cmdsynopsis><command>DIR [<pathlist>]</command> +</cmdsynopsis> +<para> +Displays the name, size, and variable storage requirement of each +procedure presently in the workspace. The current working procedure has +an asterisk before its name. All packed procedures have a dash before their +name (see PACK). The available free memory within the workspace is also +given. If a pathlist is specified, output is directed to that file or device. +</para> +<para> +A question mark next to a data storage size means the workspace does not +have enough free memory to run that procedure. +</para> +<para> +Note: This command should not be confused with the OS-9 "DIR" command. +They have completely different functions. +</para> + +<cmdsynopsis> +<command>EDIT [<procname>]</command> +<sbr> +<command>E [<procname>]</command> +</cmdsynopsis> +<para> + +Exits command mode and enters the text editor/compiler mode. If the specified +procedure does not exist, a new one is created. See the Chapter 4 for a +complete description of how edit mode works. +</para> +<para> +Examples: +<informalexample> +<programlisting> +E newprog +EDIT printreport +</programlisting> +</informalexample> + +</para> +<cmdsynopsis> +<command>KILL [<procname> {,<procname>}]</command> +<sbr> +<command>KILL*</command> +</cmdsynopsis> +<para> +Erases the procedure(s) specified. KILL* clears the +entire workspace. The process may take some time if there are many +procedures in the workspace. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +kill formulas +kill prog1, prog2, prog7 +</programlisting> +</informalexample> +</para> + +<cmdsynopsis> +<command>LIST [<procname> {,<procname>}] [> <pathlist>]</command> +<sbr> +<command>LIST* [<pathlist>]</command> +</cmdsynopsis> +<para> +Prints a formatted "pretty printed" listing of one or more procedures. +The listing includes +the relative I-code storage addresses in hexadecimal format in the first +column. The second column is reserved for program line numbers (if line +numbers are used). +</para> +<para> +If a pathlist is given, the listing is output to that file or device. This option +is commonly used to print hard-copy listings of programs. + +The LIST, SAVE and PACK commands all have identical syntax, except +that LIST prints on the OS-9 standard error path (#2) if no pathlist is given. +The files produced are formatted differently, but the function is similar. + +<important> +<para> +If an "*" is used with LIST, SAVE or PACK, the file name +immediately follows WITHOUT a greater-than sign ">" before it! +</para> +</important> + +Examples: + +<informalexample> +<programlisting> +list* /p +list prog2,prog3 >/p +list prog5 >temp +</programlisting> +</informalexample> + +</para> + +<cmdsynopsis> +<command>LOAD <pathlist></command> +</cmdsynopsis> +<para> +Loads all procedures from the specified file into the workspace. As +procedures are loaded, their names are displayed. If any of the procedures +being loaded have the same name as a procedure already in the workspace, +the existing procedures are erased and replaced with the procedure +being loaded. +</para> +<para> +If the workspace fills up before the last procedure in the file is loaded, an +error (#32) is given. In this case, not all procedures may have been loaded, +and the one being loaded when the workspace became full may not be +completely loaded. You should KILL the last procedure, use the MEM +command to get more memory or KILL unnecessary procedure(s) to free +up space, and then LOAD the file again. +</para> +<para> +Example: + +<informalexample> +<programlisting> +load quadratics +</programlisting> +</informalexample> + +</para> +<cmdsynopsis> +<command>MEM</command> +<sbr> +<command>MEM [<number>]</command> +</cmdsynopsis> +<para> +MEM used without a number displays the present total workspace size in +(decimal) bytes. If a number is given, &b09; asks OS-9 to expand or +contract the workspace to that size. A hex value can be used if preceded by +a dollar sign. If MEM responds with What?, you either asked for more +memory than is available, tried to give back too much memory (there has +to be enough to store all procedures in the workspace), or gave an +invalid number. +</para> +<para> +Example: + +<informalexample> +<programlisting> +MEM 18000 +</programlisting> +</informalexample> + +</para> +<cmdsynopsis> +<command>PACK [<procname> {,<procname>}] [> <pathlist>]</command> +<sbr> +<command>PACK* [<pathlist>]</command> +</cmdsynopsis> +<para> +This command + causes an extra compiler pass on the procedure(s) specified, which +removes names, line numbers, non-executable statements, etc. The result is +a smaller, faster procedure(s) that CANNOT be edited or debugged but can be +executed by &b09; or by the &b09; run-time-only program called "RunB". +If a pathlist is not given, the name of the first procedure in the list will be +used as a default pathname. +The procedure is written to the file/device specified in OS-9 memory +module format suitable for loading in ROM or RAM outside the +workspace. +THE RESULTING FILE CANNOT BE LOADED INTO THE WORKSPACE LATER ON, +so you should always perform a regular SAVE before PACKing a procedure! +</para> +<para> +&b09; will automatically load the packed procedure when you try +to run it later. Here is an example sequence that demonstrates packing a +procedure: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="2in"> +<tbody> +<row> +<entry>pack sort</entry> +<entry>packs procedure sort and creates a file</entry> +</row> +<row> +<entry>kill sort</entry> +<entry>kills procedure inside the workspace</entry> +</row> +<row> +<entry>run sort</entry> +<entry>run (sort is loaded outside of the workspace)</entry> +</row> +<row> +<entry>kill sort</entry> +<entry>done; delete "sort" from outside memory</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +The last step (kill) does not have to be done immediately if you will use the +procedure again later, but you should kill it when you are done so its +memory can be used for other purposes. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +pack proc1,proc2 >packed.programs + +pack* packedfile +</programlisting> +</informalexample> +</para> + +<cmdsynopsis> +<command>RENAME <procname>,<new procname></command> +</cmdsynopsis> +<para> + +Changes the name of a procedure. Can be used to allow two +copies of the same procedure in the workspace under different names. +</para> +<para> +Example: + +<informalexample> +<programlisting> +rename thisproc thatproc +</programlisting> +</informalexample> +</para> + +<cmdsynopsis> +<command>RUN [<procname> [ ( <expr> , {<expr>} ) ]]</command> +</cmdsynopsis> +<para> +Runs the procedure specified. Technically speaking, &b09; then +leaves Command mode and enters Execution mode. +</para> +<para> +A parameter list can be used to pass expected parameters to the procedure +in the same way a RUN statement inside a +procedure calls another procedure except for the restriction that all +parameters must be constants or expressions without variables. See the +PARAM statement description. +Assembly language procedures cannot be run from command mode. +</para> +<para> +The procedure called can be normal or "packed". If the procedure is not +found inside &b09;'s workspace, &b09; will call OS-9 to attempt to LINK +to an external (outside the workspace) module. If this fails, &b09; +attempts to LOAD the procedure from a file of the same name. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +run getdata + +run invert("the string to be inverted") + +run power(12,354.06) + +run power($32, sin(pi/2)) +</programlisting> +</informalexample> +</para> + +<cmdsynopsis> +<command>SAVE [<procname> { <procname>} [> <pathlist>]]</command> +<sbr> +<command>SAVE* [<pathlist>]</command> +</cmdsynopsis> +<para> +Writes the procedure(s) (or all procedures) to an output +file or device in source format. SAVE is similar to the LIST command +except the output is not formatted and I-code addresses are not included. If +a pathlist is not specified, it defaults to the name of the first +procedure listed. +</para> +<para> +If a file of the same name already exists, SAVE will prompt with: +<screen> +rewrite? +</screen> +You may answer "Y" for yes which causes the existing file to be rewritten +with the new procedure(s); or "N" to cancel the SAVE command. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +save proc2 proc3 proc4 >monday.work + +save* newprogram + +save + +save >testprogram +</programlisting> +</informalexample> +</para> +</sect1> +</chapter> +<chapter> +<title>Edit Mode</title> +<para> +Edit Mode (also called "The Editor") is used to enter or modify +&b09; procedures. It is entered from Command Mode by the EDIT (or E) command. +As soon as Edit Mode is entered, prompts change from "B:" to "E:" +If you have used a +text editor before, you will find the &b09; editor similar to many others +except for these two differences: + +<orderedlist numeration="arabic"> +<listitem> +<para> +The editor is both "string" and "line number" oriented. The use of line numbers +is optional and text can be corrected without re-typing the entire line. +</para> +</listitem> + +<listitem> +<para> +The editor is interfaced to the &b09; compiler and "decompiler". This +lets &b09; do continuous syntax error checking and permits +programs to be stored in memory in a more compact, compiled form. +</para> +</listitem> +</orderedlist> + +</para> +<sect1><title>Overview of Edit Commands</title> +<para> +The Editor includes the following commands. Each command is described +in detail later in this chapter. + +<table frame="none"> +<title>Edit Mode Commands</title> +<tgroup cols="2"> +<colspec colwidth="2in"> +<tbody> +<row> +<entry><cr></entry> +<entry>move edit pointer forward</entry> +</row> +<row> +<entry>+</entry> +<entry>move edit pointer forward</entry> +</row> +<row> +<entry>+*</entry> +<entry>move edit pointer to end of text</entry> +</row> +<row> +<entry>−</entry> +<entry>move edit pointer backward</entry> +</row> +<row> +<entry>−*</entry> +<entry>move edit pointer to beginning of text</entry> +</row> +<row> +<entry><space> <text></entry> +<entry>insert unnumbered line</entry> +</row> +<row> +<entry><line#> <text></entry> +<entry>insert or replace numbered line</entry> +</row> +<row> +<entry><line#> <cr></entry> +<entry>find numbered line</entry> +</row> +<row> +<entry>c</entry> +<entry>change string</entry> +</row> +<row> +<entry>c*</entry> +<entry>change all occurence of string</entry> +</row> +<row> +<entry>d</entry> +<entry>delete line</entry> +</row> +<row> +<entry>d*</entry> +<entry>delete all lines</entry> +</row> +<row> +<entry>l</entry> +<entry>list line(s)</entry> +</row> +<row> +<entry>l*</entry> +<entry>list all lines</entry> +</row> +<row> +<entry>q</entry> +<entry>quit editing</entry> +</row> +<row> +<entry>r</entry> +<entry>renumber line</entry> +</row> +<row> +<entry>r*</entry> +<entry>renumber all lines</entry> +</row> +<row> +<entry>s</entry> +<entry>search for string</entry> +</row> +<row> +<entry>s*</entry> +<entry>search for all occurence of string</entry> +</row> +</tbody> +</tgroup> +</table> + +</para></sect1> +<sect1><title>How the Editor Works</title> +<para> +In order to understand how the editor works it is helpful to +have a general idea of what goes on inside &b09; while you are +editing procedures. &b09; programs are always stored in memory +in a compiled form called +"I-code" (short for "Intermediate Code"). I-code is a complex binary coding +system for programs that lies between your original "source" program and +the computer's native "machine language". I-code is relatively compact, can +be executed rapidly, and most importantly, can be reconstructed almost exactly +back to the original source program. The Editor is closely connected to the +"compiler" and "decompiler" systems within &b09; that translate source code +to I-Code and vice-versa. +It is this innovative system that gives &b09; its most powerful and unusual +abilities. +</para> +<para> +Whenever you enter (or change) a program line and "return", the +compiler instantly translates this text to the internal I-code form. When +&b09; needs to display program lines back, it uses the decompiler to translate the +I-code back to the original "source" format. These processes are completely +automatic and do not require any special action on your part. +</para> +<para> +This technique has several advantages. First, +it allows the text editor to report many (syntax) errors immediately so +you can correct them instantly. Secondly, +the I-code representation of a program is more compact (by about 30%) +than its original form, so you can have have larger programs in any +given amount of available memory. +</para> +<para> +When programs are listed by &b09;, it is possible they will have a +slightly different appearance than the +way they were originally typed in, but they will +<emphasis>always</emphasis> be functionally +identical to the original form. This can happen if the +original program had extraneous spaces between keywords, unnecessary +parentheses in expressions, etc. &b09; keywords are always automatically +capitalized. +</para> +<para> +When you have finished editing the procedure, use the "q" (for "quit") +command to +exit edit mode and return to the command mode. When you give the "q" command, +the compiler performs another "pass" over the entire procedure again. +At this time syntax +that extends over multiple lines is checked and errors reported. Examples +of these errors are: GOTO or GOSUB to a non-existent line, +missing variable or array declarations, improperly constructed loops, etc. +These errors are reported using an error code and the hexadecimal I-code +address of the error. For example: +<screen> +01FC ERR #043 +</screen> +This message means that error number 43 was detected in the line that +included I-code address 01FC (hexadecimal). The LIST command gives +the I-code addresses so you can locate lines with errors reported during the +compiler's second pass. +</para></sect1> +<sect1><title>Line-Number Oriented Editing</title> +<para> +As mentioned previously, the editor has the capability to work +on programs with or without line numbers (or both). +Line numbers must be positive whole numbers in the range of 1 to 32767. +</para> +<para> +If you have experience with another version of the BASIC language, this is the kind of +editing you probably used. However, well-structured programs seldom +really need line numbers. If you don't have to use line numbers, don't. +Your programs will be shorter, faster, and easier to read. +</para> +<para> +The line-number oriented commands are: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="2in"> +<tbody> +<row> +<entry><line#> <text></entry> +<entry>insert or replace numbered line</entry> +</row> +<row> +<entry><line#> <cr></entry> +<entry>find numbered line</entry> +</row> +<row> +<entry>d</entry> +<entry>delete line</entry> +</row> +<row> +<entry>r</entry> +<entry>renumber line</entry> +</row> +<row> +<entry>r*</entry> +<entry>renumber all lines</entry> +</row> +</tbody> +</tgroup> +</informaltable> +</para> +<para> +To enter or replace a numbered line, simply type in the line +number and statement. Numbered lines can be entered in any order, but will +be automatically stored in ascending sequence. To move to a numbered +line, type the line number followed by a carriage return. The editor will move +to that line (or the line with the next higher number if the specified number +is not found) and print it. The line may be deleted using the "d" command. +</para> +<para> +The "r" renumber command will uniformly resequence all numbered lines and +lines that refer to numbered lines. Its formats are: +<programlisting> +r [ <beg line #> [,<incr> ] ] <CR> +r*[ <beg line #> [,<incr> ] ] <CR> +</programlisting> + +The first format renumbers the program starting at the current line and +forward. Lines are renumbered using +<beg line#> as the initial line number. <incr> is added to the previous line +number for the next line's number. For example, +<programlisting> +r 200,5 +</programlisting> +will give the first line number 200, the second 205, the third 210, etc. +If <beg line#> and/or <incr> are not +specified, the values 100 and 10, respectively, are assumed. +The second form of the command is identical exect it renumbers all lines in the procedure. + +</para></sect1> +<sect1><title>String-Oriented Editing</title> +<para> + + +Most editor commands are string-oriented. This means that you can enter or +change whole or partial lines without using line numbers at all. You will +find that string-oriented editing is generally faster and more convenient. +</para> +<para> +Because line numbers are not used, there has to be another way +to tell &b09; what place in the program to work on. To do this, +the editor maintains an "edit pointer" that +indicates which line is the present working location within the procedure, +and commands start workin at this point. +The editor shows you the location of the edit pointer by displaying an +"*" at the left side of the program line where the edit pointer is +presently located. +</para> +<sect2><title>Moving the Edit Pointer</title> +<para> +The "+" and "−" are used to reposition the edit pointer: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="2in"> +<tbody> +<row> +<entry>−</entry> +<entry>moves backward one line</entry> +</row> +<row> +<entry>− <number></entry> +<entry>moves backward n lines</entry> +</row> +<row> +<entry>−*</entry> +<entry>moves to the beginning of the procedure</entry> +</row> +<row> +<entry>+</entry> +<entry>moves forward one line</entry> +</row> +<row> +<entry>+ <number></entry> +<entry>moves forward N lines</entry> +</row> +<row> +<entry>+*</entry> +<entry>moves to the end of procedure</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +The number indicates how many lines to move. Backward means +towards the first line of the procedure. If the number is omitted, +a count of one is used (this is true of most edit commands). +A line consisting of a carriage return only also moves the pointer forward one +line, which makes it easy to step through a program one line at a time. +Therefore, the following commands all do the same thing: + +<programlisting> +<CR> ++ <CR> ++1 <CR> +</programlisting> + + +</para></sect2> +<sect2><title>Inserting Lines</title> +<para> +The Insert Line function consists of a "space" followed by a &b09; statement +line. The statement is inserted just ahead of the edit pointer position. (the +space itself is not inserted). +</para></sect2> +<sect2><title>Deleting Lines</title> +<para> + + +The "d" command is used to delete one or more lines. Its format is: + +<programlisting> +d [<number>] <CR> +d* +</programlisting> + +The first form deletes the <number> of lines starting at the current edit +pointer location. +The second form deletes ALL lines in the procedure (caution!). +The editor accepts +"+*" and "−*" to mean to the end, or to the beginning of the procedure +respectively. If the number is negative, that many lines BEFORE the +current line is deleted. +If a line number is omitted, only the current line is deleted. +</para></sect2> +<sect2><title>Listing Lines</title> +<para> + + +The "l" command is used to display one or more lines. +It also has the forms: +<programlisting> +l [<number>] <CR> +l* +</programlisting> +The first form will display the <number> of lines starting at the current +edit pointer position. If the number is NEGATIVE, previous lines +will be listed. + +The second form displays the entire procedure. Neither change the +edit pointer's position. The line that is the present position of the edit +pointer is displayed with a leading asterisk. + +</para></sect2> +<sect2><title>Search: Finding Strings</title> +<para> +What's a string? A string is a sequence of one or more characters that +can include letters, numbers, or punctuation in any combination. Strings +are very usefull because they allow you to change or locate just part +of a statement without having to type the whole thing. + +In the Editor, strings must be surrounded by two matching punctuation +characters (called <emphasis>delimiters</emphasis>) so the editor +knows where the string begins and ends. +The characters used for delimiters are not considered part of the string +and cannot also appear within the string. +Strings used by the Editor should not be confused with &b09;'s data type +which is also called STRING — they are different creatures. +</para> +<para> +The "s" command may be used to locate the next occurrence or all +occurrences of a string. The format for this command is: + +<programlisting> +s <delim> <match str> [<delim>] <CR> +s*<delim> <match str> [<delim>] <CR> +</programlisting> + +The first format searches for the <match str> starting on the current +edit pointer line onward. If any line at or following the edit pointer +includes a sequence of characters that match the search string, the edit +pointer is moved to that line and the line is displayed. If the string +cannot be located, the message: + +<screen> +CAN'T FIND: "<match str>" +</screen> +will be displayed and the edit pointer will remain at its original +position. The "s*" variation searches for all occurrences of the string +in the procedure starting at the present edit pointer and displays all +lines it is found in. The edit pointer ends up at the last line the +string occurred in. +</para> +<para> +Here are some examples: + +<informalexample> +<programlisting> +E:s/counter/ Looks for the string: counter + +E:s.1/2. Looks for the string: 1/2 + +E:s?three blind mice? Looks for the string: three blind mice +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>Change: String Substitution</title> +<para> +The "c" change string function is a very handy tool that +can eliminate a tremendous amount of typing. +It allows strings within lines to be located, removed, and replaced by +another string. This command is very commonly used for things like: +fixing lines with errors +without having to retype the entire line, changing a variable name +throughout a program, etc. Its formats are: +<programlisting> +c <delim> <match str> <delim> <repl str> [<delim>] <CR> +c*<delim> <match str> <delim> <repl str> [<delim>] <CR> +</programlisting> +In the first form, the editor looks for the first occurrence of the +match string starting at the present edit pointer position. If found, +the match string is removed from the line and the replacement string is +inserted in its place. The second form works the same way, but changes +ALL occurrences of the match string in the procedure starting at the +present edit pointer position. +</para> +<para> +The "c*" command will stop anytime it finds or causes a line with an error. +It cannot be used to find or change line numbers. +</para> +<para> +A word of warning: +sometimes you can inadvertently change a line you did't +intend to change because the match string is imbedded in a longer string. +For example, if you attempt to change "no" to "yes" and the word "normal" +occurs before the "no" you are looking for, "normal" will change to "yesrmal". +</para> +<para> +Examples: + +<informalexample> +<programlisting> +c/xval/yval/ +c*,GOSUB 5300,GOSUB 5500 +</programlisting> +</informalexample> +</para> +</sect2> +</sect1> +</chapter> + + +<chapter> +<title>Execution Mode</title> + +<sect1><title>Running Programs</title> +<para> +To run a &b09; procedure, enter: + +<programlisting> +RUN <procname> +</programlisting> + +If the procedure you want to run was the last procedure edited, listed, +saved, etc., you can type RUN without giving a procedure name (the +"*" shown in the DIR command identifies this procedure). +</para> +<para> +If the procedure expects <emphasis>parameters</emphasis> (see Chapter 7), +they can be given on the same +command line, however they must all be constant numbers or strings, as +appropriate, and must be given in the correct order. For example: + +<programlisting> +RUN add(4,7) +</programlisting> + +is used to call a program that expects parameter, such as +<programlisting> +PROCEDURE add +PARAMETER a,b a,b will receive the values 4,7 +PRINT a+b +END +</programlisting> + +The ability to pass parameters to a program allows you to specifically +initialize program variables. Sometimes certain procedures are parts of a +larger software system and are designed to be called from other +procedures. You can use this feature to individually test such procedures by +passing them test values as parameters. +</para> +<para> +The RUN statement causes &b09; to enter <emphasis>Execution Mode</emphasis>, +causing the procedure to run until one of the these things happen: +<orderedlist numeration="arabic"> +<listitem><para>an END or STOP statement is executed</para></listitem> +<listitem><para>you type [Ctrl-E]</para></listitem> +<listitem><para>a run-time error occurs</para></listitem> +<listitem><para>you type [Ctrl-C] (keyboard interrupt)</para></listitem> +</orderedlist> +In cases 1 and 2, you will return to system mode. In +cases 3 and 4, you will enter DEBUG mode. +</para></sect1> +<sect1><title>Execution Mode: Technically Speaking</title> +<para> + + +The RUN statement is simple and normally you do not need to know what +is happening inside &b09; when you use it. The technical description of +execution mode that follows is given for the benefit of advanced +&b09; programmers. +</para> +<para> +Execution mode is &b09;'s state when you run any procedure. It involves +executing the I-code of one or more procedures inside or outside the +workspace. Many procedures can be in use because they can call each +other (or themselves) and nest exactly like subroutines. + +You can enter execution mode in a number of ways: +<orderedlist numeration="arabic"> +<listitem><para>By means of the RUN system command.</para></listitem> +<listitem><para>By &b09;'s auto-run feature.</para></listitem> +</orderedlist> +The Auto-run feature allows &b09; to get the name of a file to load and +run from the same command line used to call &b09;. The file loaded and run +can be either a SAVED file (in the data directory), or a PACKED file (in the +execution directory). The file may contain several procedures; the one +executed is the one with the same name as the file. Parameters may be +passed following the pathname specified. For +example, the following OS-9 command lines use this feature: + +<programlisting> +OS9: &b09; printreport("Past Due Accounts") +OS9: &b09; evaluate(COS(7.8814)/12.075,−22.5,129.055) +</programlisting> + +</para> +</sect1> +</chapter> + + +<chapter> +<title>Debug Mode</title> +<sect1><title>Overview of Debug Mode</title> +<para> +One of &b09;'s outstanding features is its set of powerful <emphasis>symbolic +debugging</emphasis> commands. What is Symbolic Debugging? Simply +stated, it is testing and manipulation of programs using the +actual names and program statements used in the program. +In this chapter you will learn how Debug Mode can let you watch your +program run in slow motion you can observe each statement as +it is executed. As a bonus, you will also learn how to use the Debug Mode as +a calculator. +</para> +<para> +Debug mode is entered from execution mode in one of three ways: +<orderedlist numeration="arabic"> +<listitem> +<para> +When an error occurs during execution of a procedure (that is not +intercepted by an ON ERROR GOTO statement within the program). +</para> +</listitem> +<listitem> +<para> +When a procedure executes a PAUSE statement. +</para> +</listitem> +<listitem> +<para> +When a keyboard interrupt (control-C) occurs. +</para> +</listitem> +</orderedlist> +</para> +<para> +When any of the above happen, Debug Mode announces itself by +displaying the suspended procedure name like this: +<programlisting> +BREAK: PROCEDURE test5 +D: +</programlisting> +</para> +<para> +Notice that +Debug Mode displays a "D:" prompt when it is awaiting a +command. Any debug mode commands can the be used to examine or +change variables, turn trace mode on/off, etc. Depending on which +commands are used, execution of the program can be terminated, resumed, +or executed one source line at a time. +</para></sect1> +<sect1><title>Debug Mode Commands</title> +<para> +<cmdsynopsis> +<command>$ <text></command> +</cmdsynopsis> +Calls OS-9's Shell command interpreter to run a program or OS-9 +command. Exactly the same as the System Mode "$" command. + +<cmdsynopsis> +<command>BREAK <proc name></command> +</cmdsynopsis> +Sets up a "breakpoint" at the procedure named. This command is used +when procedures call each other, and provides a way to re-enter Debug +Mode when returning to a specific procedure. +To illustrate how BREAK works, suppose there are three procedures in the +workspace: PROC1, PROC2, and PROC3. Assume that PROC1 calls PROC2, which in +turn calls PROC3. While PROC3 is executing, you type Control-C to enter +debug mode. You can now enter: +<programlisting> +D: BREAK proc1 +ok +D: +</programlisting> +Notice that BREAK responds with "ok" if the procedure was found on the +current RUN stack. If you wish you can use the STATE command to verify that the +three procedures are "nested" as expected. +Now, you can resume execution of PROC3 by typing CONT. After PROC3 terminates, +control passes back to PROC2, which eventually returns to PROC1. As soon as +this happens, the breakpoint you set is encountered, PROC1 is suspended, +and Debug Mode is reentered. +</para> +<para> +There are three characteristics of BREAK you should note: +<orderedlist numeration="arabic"> +<listitem> +<para> +The breakpoint is removed as soon as it occurs. +</para> +</listitem> + +<listitem> +<para> +You can use one breakpoint for each active procedure. +</para> +</listitem> + +<listitem> +<para> +You can't put a breakpoint on a procedure unless it has been called but +not yet returned to. Hence, BREAK cannot be used on procedures +that have not yet been run. +</para> +</listitem> +</orderedlist> + +<cmdsynopsis> +<command>CONT</command> +</cmdsynopsis> +The command causes program execution to continue at the next +statement. It may resume +programs suspended by Control-C, PAUSE statements, BREAK command +breakpoints, or after non-fatal run-time errors. + +<cmdsynopsis> +<command>DEG</command> +<sbr> +<command>RAD</command> +</cmdsynopsis> +These commands select either degrees or radians as the angle unit +measure used by trigonometric functions. These commands only affect +the procedure currently being debugged or run. + +<cmdsynopsis> +<command>DIR [<path>]</command> +</cmdsynopsis> +Displays the workspace procedure directory in exactly the same way as the +System Mode DIR command. + +<cmdsynopsis> +<command>END or Q</command> +</cmdsynopsis> +Termintes execution of all procedures and exits Debug Mode by +returning to System Mode. Any open paths are closed at this point. + + +<cmdsynopsis> +<command>LET <var> := <expr></command> +</cmdsynopsis> +This command is essentially the same as the &b09; LET program statement, +which allows the value of a procedure variable to be set to a new value +using the result of the evaluated expression. The variable names used +in this command must be the same as in the original "source" program; +otherwise, an error is generated. LET does not work on user-defined +data structures. + + +<cmdsynopsis> +<command>LIST</command> +</cmdsynopsis> +Displays a formatted source listing of the suspended procedure with I-code +addresses. An asterisk is printed to the left of the statement where +the procedure is suspended. Only list the current procedure may be listed. + + +<cmdsynopsis> +<command>PRINT [#<expr>,] [USING <expr>,] <expr list></command> +</cmdsynopsis> +This is exactly the same as the &b09; PRINT statement and can be used +to examine the present value of variables in the suspended program. All +variable names must be the same as in the original program, and no +new variable names can be used. User-defined data structures cannot +be printed. + + +<cmdsynopsis> +<command>STATE</command> +</cmdsynopsis> + + + +This command +lists the calling ("nesting") order of all active procedures. The +highest-level procedure is always shown at the bottom of the calling list, +and the lowest-level procedure will always be the suspended procedure. +An example: +<informalexample> +<programlisting> +D:state +PROCEDURE DELTA +CALLED BY BETA +CALLED BY ALPHA +CALLED BY PROGRAM +</programlisting> +</informalexample> + + +<cmdsynopsis> +<command>STEP [<number>] or <CR></command> +</cmdsynopsis> +This command allows the suspended procedure to be executed one or +more source statements at a time. +For example, "STEP 5" would execute the equivalent of the next 5 source +statements. A debug command line which is just a carriage return is +considered the same as "STEP 1". The STEP command is most commonly +used with the trace +mode on, so the original source lines can be seen as they +are executed. +</para> +<para> +Note: because compiled I-code contains actual statement memory addresses, +the "top" or "bottom" statements of loop structures are usually executed +just once. For example, in FOR...NEXT loops the FOR statement is executed +once, so the statement that appears to be the top of the loop is actually +the one following the "FOR" statement. + +<cmdsynopsis> +<command>TRON</command> +<sbr> +<command>TROFF</command> +</cmdsynopsis> +These commands turn the suspended procedure's trace mode on and off. In +trace mode, the compiled code of each equivalent statement line is +reconstructed to source statements and displayed before the statement +is executed. If the statement causes the evaluation of one or more +expressions, an equal sign and the expression result(s) are displayed +on the following line(s). +</para> +<para> +Trace mode is local to a procedure. If the suspended procedure calls +another, no tracing occurs until control returns back +(unless of course, other called procedure(s) have trace mode on). +</para></sect1> +<sect1><title>Debugging Techniques</title> +<para> + +If your program does not do what you expect it to, it is bound to show +one of two symptoms: incorrect results, or premature termination due to +an error. The second case will automatically send you into Debug Mode. +In the first case, you have to force the program into Debug Mode either +by hitting Control-C + (assuming you have time to do so), or by using Edit Mode to put +one or more PAUSE statements in the program. Once you're in Debug Mode, +you can bring its powerful commands to bear on the problem. +</para> +<para> +Usually the first step after an error stops the program is to place +a PAUSE statement at the beginning of the suspected procedure or at a place +within it where you think things begin to go amiss, and the you +rerun the program. When the program hits the PAUSE statement, and enters +DEBUG mode, it is time to turn the trace mode on and actually +watch your program run. To do so, just type: +<programlisting> +D: TRON +</programlisting> + +After you have done this, you hit the carriage return key once for every +statement. You will see the original source statement, and if expressions +are evaluated by the statement, Debug Mode will print an equal sign and +the result of the expression. Notice that some statements such as FOR +and PRINT may cause more than one expression to be evaluated. Using this +technique, you can watch your program run one step at a time until you see +where it goes wrong. But what if in the process of tracing, you encounter +a loop that works OK, but executes 200 statements repetitively? That's +a lot of carriage returns. In this case, turn the trace off (if you +want) and use the STEP command to quickly run through the loop. Then, +turn trace mode back on, and resume single-step debugging. The command +sequence for this example is: + +<programlisting> +D: TROFF +D: STEP 200 +D: TRON +</programlisting> +</para> +<para> +Don't forget that trace mode is "local" to one procedure only. If the procedure +under test returns to another procedure you need to use the BREAK +command or put a PAUSE statement in the procedure to enter Debug Mode. +If you call another procedure from the procedure being debugged, tracing will +stop when it is called until it returns. If you also want to trace the called +procedure, it will need its own PAUSE statement. + +</para></sect1> +<sect1><title>Debug Mode as a Desk Calculator</title> +<para> +The simple program listed below turns Debug Mode into a powerful desk +calculator. It's function is simple: it declares 26 working variables, +then goes into Debug Mode so you can use interactive PRINT and LET statements. + +<programlisting> +PROCEDURE Calculator +DIM a,b,c,d,e,f,g,h,i,j,k,l,m +DIM n,o,p,q,r,s,t,u,v,w,x,y,z +PAUSE +END +</programlisting> + +Recall that while in debug mode, you cannot create new variables, +hence the DIM statements that pre-define 26 working variables for you. +If you wish yu can add more or fewer variables. +The PAUSE statement causes Debug Mode to be entered. Here's a sample session: +<programlisting> +B: run calculator +BREAK: PROCEDURE Calculator +D:let x:=12.5 +D:print sin(pi/2) +.7071606781 +D:let y:=exp(4+0.5) +D:print x,y +12.5 90.0171313 +D:Q +B: +</programlisting> +</para> +<para> +Don't forget that +the Debug Mode PRINT command can use PRINT USING to +produce formatted output (including hexadecimal). +</para> +<para> +By adding less than a dozen statements to the program, you can +make it store its variables on a disk file so they're remembered +from session to session. There are also many other enhancement +possibilities +</para> +</sect1> +</chapter> + + + +<chapter> +<title>Data Types, Variables and Data Structures</title> + +<sect1><title>Why are there different data types?</title> +<para> +A computer program's primary function is to +process data. The performance of the computer, and even +sometimes whether or not a computer can handle a particular problem, +depends on how the software stores data in memory and operates on it. +&b09; offers many possibilities for organizing and manipulating data. +</para> +<para> +Complicating matters somewhat is the fact that there are many kinds +of data. Some data are numbers used for counting or measuring. Another +example is textual data composed of letters, punctuation, etc., such +as your name. Seldom can they be mixed (for example multiplication is +meaningless to anything but numbers), and they have different storage +size requirements. Even within the same general kind of data, it is +frequently advantageous to have different ways to represent data. For +example, &b09; lets you chose from three different ways to represent +numbers - each having its own advantages and disadvantages. The decision +to use one depends entirely on the specific program you are writing. In +order for you to select the most appropiate way to store data variables, +&b09; provides five different basic data types. &b09; also lets you create +new customized data types based on combinations of the five basic types. +A good analogy is to consider the five basic types to be atoms, and the +new types you create as molecules. This is why the five basic types are +called <emphasis>atomic data types</emphasis>. +</para></sect1> +<sect1><title>Data Structures</title> +<para> +A <emphasis>data structure</emphasis> refers to storage for +more than one data item under a single name. Data +structures are often the most practical and convenient way to organize large +amounts of similar data. +The simplest kind of data structure is the <emphasis>array</emphasis>, +which is a table of values. +The table has a single name, and the storage space for each individual +value is numbered. Arrays are created by DIM statements. +For example, to create an array having five storage spaces called "AGES", +we can use the statement: + +<programlisting> +DIM AGES(5):INTEGER +</programlisting> +"(5)" tells &b09; how many spaces to reserve. The ":INTEGER" part +indicates the array's data type. To assign a value of 22 to the third +storage space in the array we can use the statement: + +<programlisting> +LET AGES(3):=22 +</programlisting> + +As you shall see, &b09; lets you create complex arrays and +even arrays that have different data types combined. +</para> +<sect2><title>Atomic Data Types</title> +<para> +&b09; includes five atomic data types: BYTE, INTEGER, REAL, +STRING and BOOLEAN. The first three types are used to represent +numbers, The STRING type is used to represent character data, and +the BOOLEAN type is used to represent the logical values of either +TRUE or FALSE. Arrays of any of these data types can be created +using one, two, or three dimensions. The table below gives an +overview of the characteristics of each type: + +<table frame="none"> +<title>&b09; Atomic Data Type Summary</title> +<tgroup cols="3"> +<colspec colwidth="1.2in"> +<colspec colwidth="2.1in"> +<thead> +<row> +<entry>Type:</entry> +<entry>Allowable values:</entry> +<entry>Memory requirement:</entry> +</row> +</thead> +<tbody> +<row> +<entry>BYTE</entry> +<entry>Whole Numbers 0 to 255</entry> +<entry>One byte</entry> +</row> +<row> +<entry>INTEGER</entry> +<entry>Whole Numbers 32768 to 32767</entry> +<entry>Two bytes</entry> +</row> +<row> +<entry>REAL</entry> +<entry>Floating Point +/ 1*10^38</entry> +<entry>Five bytes</entry> +</row> +<row> +<entry>STRING</entry> +<entry>Letters, digits, punctuation</entry> +<entry>One byte/character</entry> +</row> +<row> +<entry>BOOLEAN</entry> +<entry>True or False</entry> +<entry>One byte</entry> +</row> +</tbody> +</tgroup> +</table> +Why are there three different ways to represent numbers? Although REAL +numbers appear to be the most versatile because they have the greatest +range and are floating-point, arithmetic operations involving them are +relatively slower (by a factor of about four) compared to the INTEGER +or BYTE types. Thus using INTEGER values for loop counters, indexing +arrays, etc. can significantly speed up your programs. The BYTE type +is not appreciably faster than INTEGER, it conserves memory space in +some cases and serves as a building block for complex data types in +other cases. If you neglect to specify the type of a variable, &b09; +will automatically use the REAL data type. +</para></sect2> +<sect2><title>Type BYTE</title> +<para> +BYTE variables hold integer values in the range 0 through 255 +(unsigned 8-bit data) which are +stored as a single byte. BYTE values are always converted to another type +(16-bit integer +values and/or real values) for computation, thus they have no speed +advantage over other numeric types. However, BYTE variables require +only half of the storage used by integers, and an 1/5 of that used by reals. +Attempting to store an integer value outside the BYTE range to a BYTE +variable results in the storage of the least-significant 8-bits (the value +modulo 256) without error. + +</para></sect2> +<sect2><title>Type INTEGER</title> +<para> +INTEGER variables consist of two bytes of storage, and hold a +numeric value in the range 32768 through 32767 as +signed 16-bit data. Decimal points are not allowed. INTEGER constants +may also be represented as hexadecimal values in the range $0000 +through $FFFF to facilitate address calculations. INTEGER values +are printed without a decimal point. INTEGER arithmetic is faster and +requires less storage than REAL values. +</para> +<para> +Arithmetic which results in values outside the INTEGER range does not +cause run-time errors but instead "wraps around" modulo 65536; i.e., +32767 + 1 yields −32768. Division of an integer by another integer +yields an integer result, and any remainder is discarded. The programmer +should be aware that numeric comparisons made on values in the range +32767 through 65535 will actually be dealing with negative numbers, +so it may be desirable to limit such comparisons to tests for equality +or non-equality. Additionally, certain functions (LAND, LNOT, LOR, LXOR) +use integer values, but produce results on a non-numeric bit-by-bit basis. +</para></sect2> +<sect2><title>Type REAL</title> +<para> +The REAL data type is the default type for undeclared variables. However, +a variable may be explicitly typed REAL (for example, twopi:REAL) to +improve a program's internal documentation. REAL-type values are +always printed with a decimal point, and only those constants which +include a decimal point are actually stored as REAL values. +</para> +<para> +REAL numbers are stored in 5 consecutive memory bytes. The +first byte is the (8-bit) exponent in binary two's-complement +representation. The next four bytes are the binary sign-and-magnitude +representation of the mantissa; the mantissa in the first 31 bits, +and the sign of the mantissa in the last (least significant) bit of +the last byte of the real quantity. +<figure> +<title>Internal Representation of REAL Numbers</title> + +<literallayout> + +--------+--------+--------+--------+--------+ + |exponent| | | | |S| <- mant. sign + +--------+--------+--------+--------+--------+ +byte: +0 +1 +2 +3 +4 +</literallayout> +</figure> + +</para> +<para> +The exponent covers the range 2.938735877 * 10^−39 (2^−128) +through 1.701411835 * 10^38 (2^127) as powers of 2. Operations which +result in values out of the representation range cause overflow or +underflow errors (which may be handled automatically by the ON ERROR +command). The mantissa covers the range from 0.5 through .9999999995 +in steps of 2^-31. This means that REAL numbers can represent values +on the number line about .0000000005 apart. Operations which cause +results between the representable points are rounded to the nearest +representable number. +</para> +<para> +Floating point arithmetic is inherently inexact, thus a sequence of +operations can produce a cumulative error. Proper rounding (as +implemented in &b09;) reduces this effect but cannot eliminate it. +Programmers using comparisons on REAL quantities should use caution +with strict comparisons (i.e., = or <>), since +the exact desired value may not occur during program execution. + +</para></sect2> +<sect2><title>Type STRING</title> +<para> + + +A STRING is a variable length sequence of characters or nil (an empty +string). A variable may be defined as a STRING either explicitly (e.g., +DIM title:STRING) or implicitly by appending a dollar-sign character to +the variable name (title$ := "My First Program."). The default maximum +length allocated to each string is 32 characters, but each string may +be dimensioned less (e.g., DIM A:STRING [4]) for memory savings or more +(e.g., DIM long:STRING [2880]) to allow long strings. Notice that +strings are inherently variable-length entities, and dimensioning the +storage for a string only defines the maximum-length string which can +be stored there. When a STRING value is assigned to a STRING variable, +the bytes composing the string are copied into the variable storage +byte-by-byte. The beginning of a string is always character number one, +and this is NOT affected by the BASE0 or BASE1 statements. Operations +which result in strings too long to fit in the dimensioned storage +truncate the string on the right and no error is generated. +</para> +<para> +Normally the internal representation of the string is hidden. A string +is stored in a fixed-size storage area and is represented by a sequence +of bytes terminated by the value zero or by the maximum length allocated +to the STRING variable. Any remaining "unused" storage after the zero +byte allows the stored string to expand and contract during execution. + +The example below shows the internal storage of a variable dimensioned as +STRING[6] and assigned a value of "SAM". Notice the byte at +3 contains +the zero string terminator, and the two following bytes are not used. +<informalfigure> +<literallayout> + +--------+--------+--------+--------+--------+--------+ + | S | A | M | 00 | | | + +--------+--------+--------+--------+--------+--------+ +byte: +0 +1 +2 +3 +4 +5 +</literallayout> +</informalfigure> +If the value "ROBERT" is assigned to the variable, the zero byte terminator +is not needed because the STRING fills the storage exactly: +<informalfigure> +<literallayout> + +--------+--------+--------+--------+--------+--------+ + | R | O | B | E | R | T | + +--------+--------+--------+--------+--------+--------+ +byte: +0 +1 +2 +3 +4 +5 +</literallayout> +</informalfigure> +</para></sect2> +<sect2><title>Type BOOLEAN</title> +<para> +A BOOLEAN quantity can have only two values: TRUE or FALSE. A variable +may be typed BOOLEAN (e.g., DIM done_flag:BOOLEAN ). BOOLEAN quantities +are stored as single byte values, but they may not be used for numeric +computation. BOOLEAN values print out as the character strings: "TRUE" +and "FALSE." + +BOOLEAN values result from comparisons (comparing two compatible types), +and are appropriate for logical flags and expressions. ( result:=a AND +b AND c ). + +Do not confuse BOOLEAN operations AND, OR, XOR, and NOT (which operate +on the Boolean values TRUA end FALSE) with the logical functions LAND, +LOR, LXOR, and LNOT (which use integer values to produce results on a +bit-by-bit basis). Attempting to store a non-BOOLEAN value in a BOOLEAN +variable (or the reverse) will cause a run-time error. +</para></sect2> +<sect2><title>Automatic Type Conversion</title> +<para> +Expressions that mix numeric data types (BYTE, INTEGER, or REAL) are +automatically and temporarily converted to the largest type necessary to +retain accuracy. In addition, certain &b09; functions also perform +automatic type conversions as necessary. Thus, numeric quantities of +mixed types may be used in most cases. +Type-mismatch errors happen when an expression includes types that +cannot legally be mixed. These errors are reported by the second compiler +pass which automatically occurs when you leave EDIT mode. Type +conversions can take time. Therefore, you should use expressions +containing all values of a single type wherever possible. +</para></sect2> +</sect1> +<sect1><title>Constants</title> +<para> +Constants are frequently used in program statements and in expressions to +assign values to variables. &b09; has rules that allow you to specify +constants that correspond to the five basic data types. +</para> +<sect2><title>Numeric Constants</title> +<para> +Numeric constants can be either REAL or INTEGER. If a number constant +includes a decimal point or uses the "E format" exponential form, +it forces &b09; to +store the number in REAL format even if the value could have been +stored in INTEGER or BYTE format. +Thus, if you specifically want to specify a REAL constant, +use a decimal point (for example, 12.0). +This is sometimes done if all other values in an expression are of type +REAL so &b09; does not have to do a time-consuming type conversion +at run-time. + +Numbers that do not have a decimal point but are too large to be +represented as integers are also stored in REAL format. The following are +examples of REAL values: + +<informaltable frame="none"> +<tgroup cols="2"> +<tbody> +<row> +<entry>1.0</entry> +<entry>9.8433218</entry> +</row> +<row> +<entry>−.01</entry> +<entry>−999.000099</entry> +</row> +<row> +<entry>100000000</entry> +<entry>5655.34532</entry> +</row> +<row> +<entry>1.95E+12</entry> +<entry>−99999.9E-33</entry> +</row> +</tbody> +</tgroup> +</informaltable> + + +</para> +<para> + +Numbers that do not have a decimal point and are in the range of +32768 to +32767 are treated as INTEGER numbers. +&b09; will also accept integer constants in hexadecimal in the range 0 to +$FFFF. Hex numbers must have a leading dollar sign. Here are some +examples of INTEGER constants: + +<informaltable frame="none"> +<tgroup cols="3"> +<tbody> +<row> +<entry>12</entry> +<entry>−3000</entry> +<entry>64000</entry> +</row> +<row> +<entry>$20</entry> +<entry>$FFFE</entry> +<entry>$0</entry> +</row> +<row> +<entry>0</entry> +<entry>−12</entry> +<entry>−32768</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +</para></sect2> +<sect2><title>Boolean Constants</title> +<para> +The two legal boolean constants are "TRUE" and "FALSE". +</para> +<para> +Example: +<programlisting> +DIM flag, state: BOOLEAN +flag := TRUE +state := FALSE +</programlisting> + +</para></sect2> +<sect2><title>String Constants</title> +<para> +String constants consist of a sequence of any characters enclosed in +double quote characters. The binary value of each character byte can be +1 to 255. Double quote characters to be included in the string use two +characters in a row to represent one double quote. + +The null string "" is important because it represents a string having no +characters. It is analogous to the numeric zero. Here are some examples +of string constants: + +<programlisting> +"&b09; is a new microcomputer language" +"AABBCCDD" +"" (a null string) +"An ""older man"" is wiser" +</programlisting> + +</para></sect2> +</sect1> +<sect1><title>Variables</title> +<para> +Each &b09; variable is "local" to the procedure where it is defined. This +means that it is only known to the program statements within that +procedure. You can use the same variable name in several procedures and +the variables will be completely independent. If you want other procedures +to be able to share a variable, you must use the RUN and PARAM statements +to pass the variable when a procedure calls another procedure. +</para> +<para> +Storage for variables is allocated from the &b09; workspace when +the procedure is called. It is not possible to force a variable to +occupy a particular absolute address in memory. When the procedure +is exited, variable storage is given back and the values stored in +it are lost. Procedures can call themselves (this is referred to as +<emphasis>recursion</emphasis>) which causes another separate +storage space for variables to be allocated. + + +<warning> +<para> +&b09; does not automatically initialize +variables. When a procedure is run, all variables, arrays, and +structures will have random values. Your program must assign +any initial value if needed. +</para> +</warning> + +</para></sect1> +<sect1><title>Parameter Variables</title> +<para> +Procedures may pass variables to other procedures. When this occurs, the +variables passed to the called procedure are called "parameters". +Parameters may be passed either "by reference", +allowing values to be returned from the called procedure, or +"by value", which protects the values in the calling procedure such +that they may not be changed by the procdure which is called. +</para> +<para> +Parameters are usually passed "by reference"; this is done by enclosing +the names of the variables to be sent to the called procedure in +parentheses as part of the RUN statement. The storage address of each +parameter variable is evaluated and sent to the called procedure, which +then associates those addresses with names in a local PARAM statement. +The called procedure uses this storage as if it had been created locally +(although it may have a new name) and can change the values stored there. +Parameters passed by reference allow called procedures to return values +to their callers. +</para> +<para> +Parameters may be passed "by value" by writing the value to be passed +as an expression which is evaluated at the time of the call. Useful +expression-generators that do not alter values are +0 for numbers or +"" +for strings. For example: + +<informalexample> +<programlisting> +RUN inverse(x) passes x by reference. +RUN inverse(x+0) passes x by value. +RUN translate(word$) passes word$ by reference. +RUN translate(word$+"") passes word$ by value. +</programlisting> +</informalexample> +</para> +<para> +When parameters are passed by value, a temporary variable is created +when the expression is evaluated. The result is placed in this new temporary +storage. The address of this temporary storage is sent to the called +procedure. Therefore, the value actually given to the called procedure is a +<emphasis>copy</emphasis> of the result, and the called procedure can't +accidentially (or otherwise) change the variable(s) in the calling program. +</para> +<para> +Notice that expressions containing numeric constants are either of type +INTEGER or of type REAL; there is no type BYTE constant. Thus, BYTE-type +VARIABLES may be sent to a procedure as parameters; but expressions will +be of types INTEGER or REAL. For example, a RUN statement may evaluate +an INTEGER as a parameter and send it to the called procedure. If the +called procedure is expecting a BYTE-type variable, it uses only the +high-order byte of the (two-byte) INTEGER (which, if the value was +intended to be in BYTE-range, will probably be zero!). +</para></sect1> +<sect1><title>Arrays</title> +<para> +The DIM statement can create arrays of from 1 to 3 dimensions +(a one-dimensional array is often called a "vector", while a 2 or 3 +dimensional array is called a "matrix" ). The sizes of each dimension are +defined when the array is typed (e.g., DIM plot(24,80):BYTE) by including +the number of elements in each dimension. Thus, a table dimensioned +(24,80) has 24 rows (1-24) of 80 columns (1 - 80) when accessed in the +default (BASE 1) mode. You may elect to access the elements of an array +starting at zero (BASE 0), in which case there are still 24 rows (now +0-23) and 80 columns (now 0-79). Arrays may be composed of atomic data +types, complex data types, or other arrays. +</para></sect1> +<sect1><title>Complex Data Types</title> +<para> +The TYPE statement can be used to define a new data type as a "vector" (a +one-dimensional array) of any atomic or previously-defined types. +For example: + +<informalexample> +<programlisting> +TYPE employee_rec = name:STRING; number(2):INTEGER; malesex:BOOLEAN +</programlisting> +</informalexample> + +This structure differs from an array in that the various elements may be of +mixed types, and the elements are accessed by a <emphasis>field name</emphasis> +instead of an array index. For example: + +<informalexample> +<programlisting> +DIM employee_file(250): employee_rec +employee_file(1).name := "Tex" +employee_file(20).number(2) := 115 +</programlisting> +</informalexample> +</para> +<para> +The complex structure gives the programmer the ability to store and +manipulate related values that are of many types, to create "new" +types in addition to the five atomic data types, or to create data +structures of unusual "shape" or size. Additionally, the position of +the desired element in complex-type storage is known and defined at +"compile time" and need not be calculated at "run time". Therefore, +complex structure accesses may be slightly faster than array accesses. +The elements of a complex structure may be copied to another similar +structure using a single assignment operator (:= ). An entire structure +may be written to or read from mass storage as a single entity (e.g., +PUT #2, employee_file). Arrays or complex structures may be elements +of subsequent complex structures or arrays. +</para> +</sect1> +</chapter> + + +<chapter> +<title>Expressions, Operators, and Functions</title> + +<sect1> +<title>Evaluation of Expressions</title> +<para> +Many &b09; statements evaluate <emphasis>expressions</emphasis>. The +result of an evaluation is just a value of some atomi type (e.g., REAL, +INTEGER, STRING, or BOOLEAN). The expression itself may consist of values +and operators. For example, the expression "5+5" results in an integer +with a value of ten. +</para> +<para> +A "value" can be a constant value (e.g, 5.0, 5 , "5" , or TRUE), a +variable name, or a function (e.g, SIN(x) ) which "returns" the result as +a value. An <emphasis>operator</emphasis> combines values (typically, +those adjacent to the operator) and also returns a result. +</para> +<para> +In the course of evaluating an expression, each value is copied to an +"expression stack" where functions and operators take their input values +and return results. If (as is often the case) the expression is to be +used in an assignment statement, only when the result of the entire +expression has been found is the assignment made. This allows +the variable which is being modified (assigned to) to be one of the +values in the expression. The same principles apply for numeric, string, +and boolean operators. These principles make assignment statements such +as "X=X+1" legal in all cases, even though it would not make sense in a +mathematical context. +</para> +<para> +Any expression evaluates to one of the five "atomic" data types, i.e., +real, integer, byte, boolean, or string. This does not mean, however, +that all the operators and operands in expressions have to be of an +identical type. Often types are mixed in expressions because the RESULT +of some operator or function has a different type than its operands. +An example is the "less than" operator. Here is an example: + +<informalexample> +<programlisting> +24 < 100 +</programlisting> +</informalexample> + +The "<" operator compares two numeric operands. The result of the +comparison is of type BOOLEAN; in this case, the value TRUE. +</para> +<para> +&b09; allows intermixing of the three numeric types because it performs +automatic type conversion of operands. If different types are used in an +expression, the "result" will be the same type as the operand(s) +having the largest representation. As a rule, any numeric type operand +may be used in a expression that is expected to produce a result of +type REAL. Expressions that must produce BYTE or INTEGER results must +evaluate to a value that is small enough to fit the representation. &b09; +has a complete set of functions that can perform compatible type +conversion. Type-mismatch errors are reported by the second compiler +pass when leaving Edit mode. +</para> +</sect1> +<sect1> +<title>Operators</title> +<para> +Operators take two operands (except negation) and cause some operation +to be performed producing a result, which is generally the same type +as the operands (except comparisons). The table below lists the operators +available and the types they accept and produce. +"NUMERIC" refers to either BYTE, INTEGER, or REAL types. +<table frame="none"> +<title>&b09; Expression Operators</title> +<tgroup cols="4"> +<colspec colwidth="0.8in"> +<thead> +<row rowsep="1"> +<entry>Operator</entry> +<entry>Function</entry> +<entry>Operand type</entry> +<entry>Result type</entry> +</row> +</thead> +<tbody> +<row> +<entry>−</entry> +<entry>Negation</entry> +<entry>NUMERIC</entry> +<entry>NUMERIC</entry> +</row> +<row> +<entry>^ or **</entry> +<entry>Exponentiation</entry> +<entry>NUMERIC (positive)</entry> +<entry>NUMERIC</entry> +</row> +<row> +<entry>*</entry> +<entry>Multiplication</entry> +<entry>NUMERIC</entry> +<entry>NUMERIC</entry> +</row> +<row> +<entry>/</entry> +<entry>Division</entry> +<entry>NUMERIC</entry> +<entry>NUMERIC</entry> +</row> +<row> +<entry>+</entry> +<entry>Addition</entry> +<entry>NUMERIC</entry> +<entry>NUMERIC</entry> +</row> +<row> +<entry></entry> +<entry>Subtraction</entry> +<entry>NUMERIC</entry> +<entry>NUMERIC</entry> +</row> +<row> +<entry>NOT</entry> +<entry>Logical Negation</entry> +<entry>BOOLEAN</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry>AND</entry> +<entry>Logical AND</entry> +<entry>BOOLEAN</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry>OR</entry> +<entry>Logical OR</entry> +<entry>BOOLEAN</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry>XOR</entry> +<entry>Logical EXCLUSIVE OR</entry> +<entry>BOOLEAN</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry>+</entry> +<entry>Concatenation</entry> +<entry>STRING</entry> +<entry>STRING</entry> +</row> +<row> +<entry>=</entry> +<entry>Equal to</entry> +<entry>ANY</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry><> or ><</entry> +<entry>Not equal to</entry> +<entry>ANY</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry><</entry> +<entry>Less than</entry> +<entry>NUMERIC, STRING*</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry><= or =<</entry> +<entry>Less than or Equal</entry> +<entry>NUMERIC, STRING*</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry>></entry> +<entry>Greater than</entry> +<entry>NUMERIC, STRING*</entry> +<entry>BOOLEAN</entry> +</row> +<row> +<entry>>= or =></entry> +<entry>Greater than or Equal</entry> +<entry>NUMERIC, STRING*</entry> +<entry>BOOLEAN</entry> +</row> +</tbody> +</tgroup> +</table> +When comparing strings, the ASCII collating sequence is used, so that +0 < 1 < ... < 9 < A < B< ... < Z < a < b< +... < z +</para> +<sect2> +<title>Operator Precedence</title> +<para> +Operators have "precedence". This means they are evaluated in a specific +order. (i.e., multiplications performed before addition). Parentheses can +be used to override natural precedence, however, extraneous parentheses +may be removed by the compiler. The legal operators are listed below, +in precedence order from highest to lowest. + +<informaltable frame="none"> +<tgroup cols="7"> +<colspec colname="c1"> +<colspec colname="c2"> +<colspec colname="c3"> +<colspec colnum=7 colname="c7"> +<spanspec spanname="firstop" namest="c2" nameend="c2"> +<spanspec spanname="secondop" namest="c3" nameend="c7"> +<spanspec spanname="onlyop" namest="c2" nameend="c7"> +<spanspec spanname="all" namest="c1" nameend="c7"> +<tbody> +<row> +<entry spanname="all">Highest Precedence</entry> +</row> +<row> +<entry spanname="firstop">NOT</entry> +<entry spanname="secondop">(negate)</entry> +</row> +<row> +<entry spanname="firstop">^</entry> +<entry spanname="secondop">**</entry> +</row> +<row> +<entry spanname="firstop">*</entry> +<entry spanname="secondop">/</entry> +</row> +<row> +<entry spanname="firstop">+</entry> +<entry spanname="secondop"></entry> +</row> +<row> +<entry spanname="firstop">></entry> +<entry><</entry> +<entry><></entry> +<entry>=</entry> +<entry>>=</entry> +<entry><=</entry> +</row> +<row> +<entry spanname="onlyop">AND</entry> +</row> +<row> +<entry spanname="firstop">OR</entry> +<entry spanname="secondop">XOR</entry> +</row> +<row> +<entry spanname="all">Lowest Precedence</entry> +</row> +</tbody> +</tgroup> +</informaltable> +</para> +<para> +Operators of equal precedence are shown on the same line, and are +evaluated left to right in expressions. The only exception to this rule is +exponentiation, which is evaluated right to left. Raising a negative number +to a power is not legal in &b09;. +</para> +<para> +In the examples below, &b09; expressions on the left are evaluated as +indicated on the right. Either form may be entered, +but the simpler form on the left will always be generated by the decompiler. +<informaltable frame="none"> +<tgroup cols="2"> +<tbody> +<row> +<entry>&b09; representation</entry> +<entry>Equivalent form</entry> +</row> +<row> +<entry>a:= b+c**2/d</entry> +<entry>a:= b+((c**2)/d)</entry> +</row> +<row> +<entry>a:= b>c AND d>e OR c=e</entry> +<entry>a:= ((b>c) AND (d>e)) OR (c=e)</entry> +</row> +<row> +<entry>a:= (b+c+d)/e</entry> +<entry>a:= ((b+c)+d)/e</entry> +</row> +<row> +<entry>a:= b**c**d/e</entry> +<entry>a:= (b**(c**d))/e</entry> +</row> +<row> +<entry>a:= (b)**2</entry> +<entry>a:= (b)**2</entry> +</row> +<row> +<entry>a:=b=c</entry> +<entry>a:= (b=c) (returns BOOLEAN value)</entry> +</row> +</tbody> +</tgroup> +</informaltable> + + +</para></sect2></sect1> +<sect1><title>Functions</title> +<para> +Functions take one or more <emphasis>arguments</emphasis> enclosed in +parentheses, perform some operation, and return a value. They may be used +as operands in expressions. Functions expect that the arguments passed +to them be expressions, constants, or variables of a certain type and +return a result of a certain type. Giving a function, an argument of an +incompatible type will result in an error. +</para> +<para> +In the descriptions of functions that follow, the following notation +describes the type required for the parameter expressions: + +<informaltable frame="none"> +<tgroup cols="2"> +<tbody> +<row> +<entry><num></entry> +<entry>means any numeric-result expression.</entry> +</row> +<row> +<entry><str></entry> +<entry>means any string-result expression.</entry> +</row> +<row> +<entry><int></entry> +<entry>means any integer-result expression.</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +The functions below return REAL results. Accuracy of transcendental +functions is 8+ decimal digits. Angles can be either degrees or radians (see +DEG/RAD statement descriptions). + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="1.5in"> +<tbody> +<row> +<entry>SIN(<num>)</entry> +<entry>trigonometric sine of <num></entry> +</row> +<row> +<entry>COS(<num>)</entry> +<entry>trigonometric cosine of <num></entry> +</row> +<row> +<entry>TAN(<num>)</entry> +<entry>trigonometric tangent of <num></entry> +</row> +<row> +<entry>ASN(<num>)</entry> +<entry>trigonometric arcsine of <num></entry> +</row> +<row> +<entry>ACS(<num>)</entry> +<entry>trigonometric arcosine of <num></entry> +</row> +<row> +<entry>ATN(<num>)</entry> +<entry>trigonometric arctangent of <num></entry> +</row> +<row> +<entry>LOG(<num>)</entry> +<entry>natural logarithm (base e) of <num></entry> +</row> +<row> +<entry>LOG10(<num>)</entry> +<entry>logarithm (base 10) of <num></entry> +</row> +<row> +<entry>EXP(<num>)</entry> +<entry>e (2.71828183) raised to the power <num>, which must be a +positive number</entry> +</row> +<row> +<entry>FLOAT(<num>)</entry> +<entry><num> converted to type REAL (from BYTE or INTEGER)</entry> +</row> +<row> +<entry>INT(<num>)</entry> +<entry>truncates all digits to the right of +the decimal point of a REAL <num></entry> +</row> +<row> +<entry>PI</entry> +<entry>the constant 3.14159265.</entry> +</row> +<row> +<entry>SQR(<num>)</entry> +<entry>square root of <num>, which must be positive.</entry> +</row> +<row> +<entry>SQRT(<num>)</entry> +<entry>square root of <num>; same as SQR.</entry> +</row> +<row> +<entry morerows="2">RND(<num>)</entry> +<entry>if <num>=0, returns random x, 0 <= x < 1.</entry> +</row> +<row> +<entry>if <num>>0, returns random x, 0 <= x < <num>.</entry> +</row> +<row> +<entry>if <num><0, use ABS(<num>) as new random number seed.</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +The following functions can return any numeric type, depending on the +type of the input parameter(s). + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="1.5in"> +<tbody> +<row> +<entry>ABS(<num>)</entry> +<entry>absolute value of <num></entry> +</row> +<row> +<entry>SGN(<num>)</entry> +<entry>signum of <num>: 1 if <num> < 0; 0 if <num> = 0; or 1 if <num> > 0</entry> +</row> +<row> +<entry>SQ(<num>)</entry> +<entry><num> squared</entry> +</row> +<row> +<entry>VAL(<str>)</entry> +<entry>convert type string to type numeric</entry> +</row> +</tbody> +</tgroup> +</informaltable> + + +The following functions can return results of type INTEGER or BYTE: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="1.5in"> +<tbody> +<row> +<entry>FIX(<num>)</entry> +<entry>round REAL <num> and convert to type INTEGER.</entry> +</row> +<row> +<entry>MOD(<num1>,<num2>)</entry> +<entry>modulus (remainder) function. <num1> mod <num2>.</entry> +</row> +<row> +<entry>ADDR(<name>)</entry> +<entry>absolute memory address of variable, array, or structure named <name>.</entry> +</row> +<row> +<entry>SIZE(<name>)</entry> +<entry>storage size in bytes of variable, array, or structure named <name>.</entry> +</row> +<row> +<entry>ERR</entry> +<entry>error code of most recent error, automatically resets to zero when referenced.</entry> +</row> +<row> +<entry>PEEK(<int>)</entry> +<entry>value of byte at memory address <int>.</entry> +</row> +<row> +<entry>POS</entry> +<entry>current character position of PRINT buffer.</entry> +</row> +<row> +<entry>ASC(<str>)</entry> +<entry>numeric value of first character of <str>.</entry> +</row> +<row> +<entry>LEN(<str>)</entry> +<entry>length of string <str>.</entry> +</row> +<row> +<entry>SUBSTR(<str1>,<str2>)</entry> +<entry>substring search: returns starting position of first occurrence of <str1> in +<str2>, or 0 if not found.</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +The following functions perform bit-by-bit logical operations on integer +or byte data types and return integer results. They should NOT be confused +with the BOOLEAN-type operators. + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="1.5in"> +<tbody> +<row> +<entry>LAND(<num>,<num>)</entry> +<entry>Logical AND</entry> +</row> +<row> +<entry>LOR(<num>,<num>)</entry> +<entry>Logical OR</entry> +</row> +<row> +<entry>LXOR(<num>,<num>)</entry> +<entry>Logical EXCLUSIVE OR</entry> +</row> +<row> +<entry>LNOT(<num>)</entry> +<entry>Logical NOT</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +These functions return a result of type STRING: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="1.7in"> +<tbody> +<row> +<entry>CHR$(<int>)</entry> +<entry>ASCII char. equivalent of <int></entry> +</row> +<row> +<entry>DATE$</entry> +<entry>date and time, format: "yy/mm/dd hh:mm:ss"</entry> +</row> +<row> +<entry>LEFT$(<str>,<int>)</entry> +<entry>leftmost <int> characters of <str>.</entry> +</row> +<row> +<entry>RIGHT$(<str>,<int>)</entry> +<entry>rightmost <int> characters of <str>.</entry> +</row> +<row> +<entry>MID$(<str>,<int1>,<int2>)</entry> +<entry>middle <int2> characters of <str> starting at +character position <int1>.</entry> +</row> +<row> +<entry>STR$(<num>)</entry> +<entry>converts numeric type <num> to displayable characters of type +STRING representing the number converted.</entry> +</row> +<row> +<entry>TRIM$(<str>)</entry> +<entry><str> with trailing spaces removed.</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +The following functions return BOOLEAN values: + + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="1.5in"> +<tbody> +<row> +<entry>TRUE</entry> +<entry>always returns TRUE.</entry> +</row> +<row> +<entry>FALSE</entry> +<entry>always returns FALSE.</entry> +</row> +<row> +<entry>EOF(#<num>)</entry> +<entry>End-of-file test on disk file path <num>, returns TRUE if +end-of-file condition</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +</para> +</sect1> +</chapter> +<chapter> +<title>Program Statements and Structure</title> +<sect1><title>Program Structure</title> +<para> +Each &b09; can be a complete program in itself, or several procedures +that call each other can be used to create an application program. It is +up to the programmer to decide which approach to take. One procedure +may suffice for small programs but large programs are easier to write +and test if divided into separate modules (procedures) according to the +program's natural flow. These suggestions reflect sound structured +programming practice. Nonetheless, you can use a single large procedure +for your program if you so desire. +</para> +<para> +A procedure consists of any number of program statement lines. Each line +can have an optional line number, and more than one program statement can be +placed on the same line if separated by "\" characters. For +example, the following statements are equivalent: + +<informaltable frame="none"> +<tgroup cols="2"> +<tbody> +<row> +<entry>GOSUB 550 \ PRINT X,Y \ RETURN</entry> +<entry><literallayout>GOSUB 550 +PRINT X,Y +RETURN +</literallayout></entry> +</row> +</tbody> +</tgroup> +</informaltable> +The maximum input line length is 255 characters. Line feeds can +be used to make a single long line into shorter lines to fit display +screens better. This is especially useful when working on hard-copy +terminals. +</para> +<para> +Program statements can be in any order consistent with program logic +Progra readability is improved if all variables are declared with +DIM statements at the beginning of the procedure, but this is not mandatory. +The program can be terminated with END or STOP statements, which are also +optional. +</para></sect1> +<sect1><title>Line Numbers</title> +<para> +Line numbers are optional. They can be any integer number in the range of +1 to 32767. Only use line numbers where absolutely necessary (such as +with GOSUB). They make programs harder to understand, use additional +memory space, and increase compile time considerably. Line numbers are +local to procedures. That is, the same line number can be used in different +procedures without conflict. +</para></sect1> +<sect1><title>Assignment Statements</title> +<para> +Assignment statements are used for computing or initializing of variables. +</para> +<sect2><title>LET Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>[LET] <var> := <expr></command> +<sbr> +<command>[LET] <var> = <expr></command> +<sbr> +<command>[LET] <struct> := <struct></command> +<sbr> +<command>[LET] <struct> = <struct></command> +</cmdsynopsis> + +</para> +<para> +This statement + evaluates an expression and stores the result in <var> which may be a +simple variable or data structure element. The result of the expression +must be of the same or compatible type as <var>. +&b09; will accept either "=" or ":=" as an assignment operator, however, the +second form ( := ) is preferred because it distinguishes the assignment +operation from a comparison (the test for equality). The ":=" operator is +the same as used in PASCAL. +</para> +<para> +Another use of the assignment statement is to copy the entire value +of an array or complex data structure to another array or complex +data structure. The data structures do not have to have the same type +or "shape". The only restriction is that the size of the destination +structure be the same or larger than the source structure. In fact this +type of assignment can be used to perform unusual type conversions. +For example, a string variable of 80 characters can be copied to a +one-dimensional array of 80 bytes. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +A := 0.1 + +value := temp/sin(x) + +DIM array1(100), array2(100) +array1 := array2 + +LET AUTHOR$ := FIRST_NAME$ + LAST_NAME$ + +DIM truth,lie:BOOLEAN +lie := 100 < 1 +truth := NOT lie + +count = total-adjustment +matrix(2).coefficient(n+2) := matrix(1).coefficient(n) +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>POKE Statement</title> +<para> + +Syntax: +<cmdsynopsis> +<command>POKE <integer expr> , <byte expr></command> +</cmdsynopsis> +This statement allows a program to store data at a specific memory +address. The first expression is used as the absolute address to store +the type BYTE result of the second expression. This statement can alter +any memory address so care must be taken when using it. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +POKE ADDR(buffer)+5,ASC("A") + +POKE 1200,14 + +POKE $1C00,$FF + +POKE pointer,PEEK(pointer+1) + +(* alternative to: alphabet$ := "ABCDEFGHIJKLMNOPQRSTUVWXYZ" *) +FOR i=0 to 25 + POKE ADDR(alphabet$)+i,$40+i +NEXT i +POKE ADDR(alphabet$)+26,$FF +</programlisting> +</informalexample> + +</para></sect2></sect1> + +<sect1><title>Control Statements</title> +<para> +This class of statements affect the (usually) sequential execution of +program statements. They are used to construct loops or make decisions +that alter program flow. &b09; provides a selection of looping statements +that allow you to create any kind of loop using sound structured +programming style. +</para> +<sect2><title>IF Statement: Type 1</title> +<para> +Syntax: + +<cmdsynopsis> +<command>IF <bool expr> THEN <line #></command> +</cmdsynopsis> +This form of the if statement causes execution to be transferred +to the statement having the line number specified if the +result of the expression is TRUE, otherwise the next sequential +statement is executed. For example: +<programlisting> +IF payment < balance then 400 +</programlisting> +</para> +</sect2> +<sect2><title>IF Statement: Type 2</title> +<para> +Syntax: +<cmdsynopsis> +<command>IF <bool expr> THEN <statements></command> +<sbr> +<command>[ ELSE <statements> ]</command> +<sbr> +<command>ENDIF</command> +</cmdsynopsis> +This kind of IF structure evaluates the expression to a BOOLEAN +value. If the result is TRUE the statement(s) immediately following +the THEN are executed. If an ELSE clause exists, statements between +the ELSE and ENDIF are skipped. If the expression is evaluated to +FALSE control is transferred to the first statement following the +ELSE, if present, or otherwise to the statement following the ENDIF. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +IF a < b THEN + PRINT "a is less than b" + PRINT "a:";a;" b:";b +ENDIF + +IF a < b THEN + PRINT "a is less than b" +ELSE + IF a=b THEN + PRINT "a equals b" + ELSE + PRINT "a is greater than b" + ENDIF +ENDIF +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>FOR/NEXT Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>FOR <var> = <expr> TO <expr> [ STEP <expr> ]</command> +<sbr> +<command>NEXT <var></command> +</cmdsynopsis> +Creates a loop that usually executes a specified number of times +while automatically increasing or decreasing a specified counter variable. +The first expression is evaluated and the result is stored in <var> which +must be a simple integer or real variable. The second expression is +evaluated and stored in a temporary variable. +If the STEP clause is used, the expression following is evaluated +and used as the loop increment. If it is negative, the loop will count down. +</para> +<para> +The "body" of the loop (i.e. statements between the "FOR" and "NEXT" are +executed until the counter variable is larger than the terminating +expression value. For negative STEP values, the loop will execute until the +loop counter is less than the termination value. If the initial value of <var> +is beyond the terminating value the body of the loop is never executed. +It is legal to jump out of FOR/NEXT loops. The is no limit to the nesting +of FOR/NEXT loops. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +FOR counter = 1 to 100 step .5 + PRINT counter +NEXT counter + + +FOR var = min1 TO min+max STEP increment-adjustment + PRINT var +NEXT var + + +FOR x = 1000 TO 1 STEP 1 + PRINT x +NEXT x +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>WHILE..DO Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>WHILE <bool expr> DO</command> +<sbr> +<command>ENDWHILE</command> +</cmdsynopsis> +This is a loop construct with the test at the "top" of the +loop. Statements within the loop are executed as long as <bool +expr> is TRUE. The body of the loop will not be executed if the +boolean expression evaluates to FALSE when first executed. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +WHILE a<b DO is equivalent to 100 IF a>=b THEN 500 + PRINT a PRINT a + a := a+1 a := a+1 +ENDWHILE GOTO 100 + 500 REM + +DIM yes:BOOLEAN +yes=TRUE +WHILE yes DO + PRINT "yes! "; + yes := POS<50 +ENDWHILE + +REM reverse the letters in word$ +backward$ := "" +INPUT word$ +WHILE LEN(word$) > 0 DO + backward$ := backward$ + RIGHT$(word$,1) + word$ := LEFT$(word$,LEN(word$)1) +ENDWHILE +word$ := backward$ +PRINT word$ +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>REPEAT..UNTIL Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>REPEAT</command> +<sbr> +<command>UNTIL <bool expr></command> +</cmdsynopsis> +This is a loop that has its test at the bottom of the loop. The +statement(s) within the loop are executed until the result of <bool expr> is +TRUE. The body of the loop is always executed at least one time. +</para> +<para> +Examples: +<informalexample> +<programlisting> +x = 0 is the same as x=0 +REPEAT 100 PRINT x + PRINT x x=x+1 + x=x+1 IF X <= 10 THEN 100 +UNTIL x>10 + +(* compute factorial: n! *) +temp := 1. +INPUT "Factorial of what number? ",n +REPEAT + temp := temp * n + n := n1 +UNTIL n <= 1.0 +PRINT "The factorial is "; temp +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>LOOP and ENDLOOP/EXITIF and ENDEXIT Statements</title> +<para> +Syntax: +<cmdsynopsis> +<command>LOOP</command> +<sbr> +<command>ENDLOOP</command> +</cmdsynopsis> + +<cmdsynopsis> +<command>EXITIF <bool expr> THEN <statements></command> +<sbr> +<command>ENDEXIT</command> +</cmdsynopsis> +These related types of statements can be used to construct +loops with test(s) located anywhere in the body of the loop. +The LOOP and ENDLOOP statements define the body of the loop. +EXITIF clauses can be inserted anywhere inside the loop to leave the loop +if the result of its test is true. +Note that if there is no EXITIF clause, you will create a loop that never ends. +</para> +<para> +The EXITIF clause evaluates an expression to a boolean result. If the +result is FALSE, the statement following the ENDEXIT is executed next. +Otherwise, the statement(s) between the EXITIF AND ENDEXIT are +executed, then control is transferred to the statement following +the body of the loop. This exit clause +is often used to perform some specific function upon termination of the +loop which depends on where the loop terminated. +</para> +<para> +EXITIF statements are almost always used when LOOP..ENDLOOP is +used, but they can also be useful in ANY type of &b09; loop +construct (e.g., FOR/NEXT, REPEAT... UNTIL, etc.). Examples: + +<informalexample> +<programlisting> +LOOP is equivalent to 100 REM top of loop + count=count+1 count=count+1 +EXITIF count >100 THEN IF COUNT <= 100 then 200 + done = TRUE done = TRUE +ENDEXIT GOTO 300 + PRINT count 200 PRINT count + x = count/2 x = count/2 +ENDLOOP GOTO 100 + 300 REM out of loop + +INPUT x,y +LOOP + PRINT +EXITIF x < 0 THEN + PRINT "x became zero first" +ENDEXIT + x := x1 +EXITIF y < 0 THEN PRINT "y became zero first" +ENDEXIT + y := y1 +ENDLOOP +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>GOTO Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>GOTO <line #></command> +</cmdsynopsis> +The GOTO unconditionally transfers execution flow to the line having the +specified number. Note that the line number is a constant, not an expression +or a variable. +</para> +<para> +Example: +<informalexample> +<programlisting> +GOTO 1000 +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>GOSUB/RETURN Statements</title> +<para> +Syntax: +<cmdsynopsis> +<command>GOSUB <line #></command> +<sbr> +<command>RETURN</command> +</cmdsynopsis> +The GOSUB statement + transfers program execution to a subroutine starting at the specified +line number. The subroutine is executed until a RETURN statement is +encountered, which causes execution to resume at the statement following +the calling GOSUB. Subroutines may be "nested" to any depth. +</para> +<para> +Example: +<informalexample> +<programlisting> + FOR n := 1 to 10 + x := SIN(n) + GOSUB 100 + NEXT n + FOR m := 1 TO 10 + x := COS(m) + GOSUB 100 + NEXT m + STOP + +100 x := x/2 + PRINT x + RETURN +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>ON GOTO/GOSUB Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>ON <int expr> GOTO <line #> {,<line #>}</command> +<sbr> +<command>ON <int expr> GOSUB <line #> {,<line #>}</command> +</cmdsynopsis> +These statements evaluate an integer expression and use the result to select +a corresponding line number from an ordered list. Control is then +transferred to that line number unconditionally in ON GOTO statements or +as a subroutine in ON GOSUB statements. +These statements are similar to CASE statements in other languages. +</para> +<para> +The expression must evaluate to a positive INTEGER-type result +having a value between 1 and n, n being the amount of line numbers in the +list. If the result has any other result, no line number is selected +and the next sequential statement is executed. +</para> +<para> +Example: + +<informalexample> +<programlisting> + (* spell out the digits 0 to 9 *) + DIM digit:INTEGER + A$="one digit only, please" + INPUT "type in a digit"; digit + ON digit+1 GOSUB 10,11,12,13,14,15,16,17,18,19 + PRINT A$ + STOP + + (* names of digits *) +10 A$ := "ZERO" + RETURN +11 A$ := "ONE" + RETURN +12 A$ := "TWO" + RETURN +13 A$ := "THREE" + RETURN +14 A$ := "FOUR" + RETURN +15 A$ := "FIVE" + RETURN +16 A$ := "SIX" + RETURN +17 A$ := "SEVEN" + RETURN +18 A$ := "EIGHT" + RETURN +19 A$ := "NINE" + RETURN +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>ON ERROR GOTO Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>ON ERROR [ GOTO <line #> ]</command> +</cmdsynopsis> +This statement sets a "trap" that transfers control to the line +number given when a non-fatal run-time error occurs. If no ON ERROR GOTO has +been executed in a procedure before an error occurs, the procedure will stop +and enter DEBUG mode. The error trap can be turned of by executing ON +ERROR without a GOTO. +</para> +<para> +This statement is often used in conjunction with the ERR function, +which returns the specific error code, and the ERROR statement +which artificially generates "errors". Note: the ERR function +automatically resets to zero any time it is called. +</para> +<para> +Example: +<informalexample> +<programlisting> + (* List a file *) + + DIM path,errnum: INTEGER, name: STRING[45], line: STRING[80] + ON ERROR GOTO 10 + INPUT "File name? "; name + OPEN #path,name:READ + LOOP + READ #path, line + PRINT line + ENDLOOP + +10 errnum=ERR + IF errnum = 211 THEN + (* end-of-file *) + PRINT "Listing complete." + CLOSE #path + END + ELSE + (* other errors *) + PRINT "Error number "; errnum + END + ENDIF +</programlisting> +</informalexample> +</para></sect2></sect1> +<sect1><title>Execution Statements</title> +<para> +Execution statements run procedures, stop execution of procedures, create +shells, or affect the current execution of the procedure. +</para> +<sect2><title>Run Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>RUN <proc name> [ ( <param> {,<param>} ) ]</command> +<sbr> +<command>RUN <string var> [ ( <param> {,<param>} ) ]</command> +</cmdsynopsis> +This statement + calls a procedure by name; when that procedure ends, control will pass +to the next statement after the RUN. It is most often used to call a +procedure inside the workspace, but it can also be used to call a previously +compiled (by the PACK command) procedure or a 6809 machine language +procedure outside the +workspace. The name can be optionally taken from a string variable. +</para></sect2> +<sect2><title>Parameter Passing</title> +<para> +The RUN statement + can include a list of parameters enclosed in parentheses to be passed to +the called procedure. The called procedure must have PARAM statements +of the same size and order to match the parameters passed to it by the +calling procedure. +</para> +<para> +The parameters can be variables, constants, or the names of entire arrays or +data structures. They can be of any type, (EXCEPT variable of type BYTE +but BYTE arrays are O.K.). +If a parameter is a constant or expression, it is passed "by value", i.e., +it is evaluated and placed in a temporary storage +location, and the address of the temporary storage is passed to the called +procedure. Parameters passed by value can be changed by the receiving +procedure, but the changes are not reflected in the calling procedure. +</para> +<para> +If the parameter is the name of a variable, array, or data structure, it is +passed by "reference", i.e., the address of that storage +is sent to the called procedure and thus the value in that storage may be +changed by the receiving procedure. These changes are reflected in the +calling procedure. +</para></sect2> +<sect2><title>Calling External Procedures</title> +<para> +If the procedure named by RUN can't be found in the workspace, &b09; +will check to see if it was loaded by OS-9 outside the workspace. If it isn't +found there, &b09; will try to find a disk file having the same name in the +current execution directory, load it, and run it. +In either case, &b09; checks to see if the called procedure is a &b09; +I-code module or a 6809 machine language module, and executes it +accordingly. If it is a 6809 machine language module, &b09; executes a +JSR instruction to its entry point and the module is executed as 6809 +native code. The machine language routine can return to the original +calling procedure by executing an RTS instruction. The diagram on the +next page shows what the stack frame passed to machine-language +subroutines looks like. +</para> +<para> +After an external procedure has been called but is no longer needed, the +KILL statement should be used to get rid of it so its memory space can be +used for other purposes. +<figure> +<title>Stack Frame Passed to Machine Language Procedures</title> +<literallayout> ++----------------------+ ^ +| | | + higher addresses + +| more parameters | + +| | ++----------------------+ --- +| | | +| size of 1st param | | ++ - - - - - - - + 4 bytes +| addr of 1st param | | +| | | ++----------------------+ --- +| | | +| parameter count | 2 bytes +| | | ++----------------------+ --- +| | | +| return address | 2 bytes +| | | ++----------------------+ --- <- 6809 Stack Pointer + Register value +</literallayout> +</figure> +</para> +<para> +Machine language modules return error status by setting the "C" +bit of the MPU condition codes register, and by setting the B +register to the appropiate error code. For an example of a machine +language subroutine ("INKEY"), See Appendix A. +</para> +<para> +Example of use of the RUN statement: + +<informalexample> +<programlisting> +PROCEDURE trig_table +num1 := 0 \ num2 := 0 +REPEAT + RUN display(num1,SIN(num1)) + RUN display(num2,COS(num2)) + PRINT +UNTIL num1 > 1 +END + +PROCEDURE display +PARAM passed,funcval +PRINT passed;":";funcval, +passed := passed + 0.1 +END +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>KILL Statement</title> +<para> +Syntax: +<cmdsynopsis> + <command>KILL <str expr></command> +</cmdsynopsis> + +This statement is used to +"unlink" an external procedure, possibly returning system memory, +and remove it from &b09;'s procedure directory. If the procedure is +inside the workspace, nothing happens and no error is generated. KILL can +be used with auto-loading PACKed procedures as an alternative to CHAIN +when program overlay is desired. +<warning> +<orderedlist numeration="arabic"> +<listitem> +<para> +It can be fatal to OS-9 to KILL a procedure that is still "active". +</para> +</listitem> +<listitem> +<para> +When KILL is used together with a RUN statement, the RUN statement MUST use the +same string variable which contains the name of the procedure. +See the first example below: +</para> +</listitem> +</orderedlist> +</warning> +Examples: +<informalexample> +<programlisting> +LET procname$="average" +RUN procname$ +KILL procname$ + +INPUT "Which test do you want to run? ",test$ +RUN test$ +KILL test$ +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>CHAIN Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>CHAIN <str expr></command> +</cmdsynopsis> +The CHAIN statement + performs an OS-9 "chain" operation on the SHELL, passing the specified +string as an argument. This causes &b09; to be exited, unlinked, +and its memory returned to OS-9. The string should evaluate to the +name of an executable module (such as &b09;), passing parameters if +appropriate. +</para> +<para> +CHAIN + can begin execution of any module, not just &b09;. It executes the +module indirectly through the Shell in order to take advantage of Shell's +parameter processing. This has the side-effect of +leaving an extra "incarnation" of the Shell active. Programs that +repeatedly chain to each other eventually find all of memory filled with +waiting shells. This can be prevented by using the "ex" option of the Shell. +Consult the OS-9 User's Guide for more details on the capabilities of the shell. +</para> +<para> +Files that are open when a CHAIN occurs are not closed. +However, the OS-9 Fork call will only pass the standard I/O paths +(0,1,2) to a child process. Therefore, if it is necesary to pass +an open path to another program segment, the "ex" option of Shell +must be used. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +CHAIN "ex &b09; menu" + +CHAIN "&b09; #10k sort (""datafile"",""tempfile"")" + +CHAIN "DIR /D0" + +CHAIN "Dir; Echo *** Copying Directory ***; ex basic09 copydir" +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>SHELL Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>SHELL <str expr></command> +</cmdsynopsis> +This statement +allows &b09; programs to run any OS-9 command or program. +This gives access to virtually any OS-9 function including +multiprogramming, utility commands, terminal, and I/O control, +and more. +Consult the "OS-9 User's Guide" for a detailed +discussion of OS-9 standard commands. +</para> +<para> +The SHELL statement requests OS-9 to create a new process, initially +executing the "shell", which is the OS-9 command interpreter. The +shell can then call any program in the system (subject to the normal +security functions). The string expression is evaluated and passed to the +shell to be executed as a command line. (just as if it had +been typed in). If the string is null, &b09; is temporarily +suspended and the shell process displays prompts +and accepts commands in its normal manner. When the shell process +terminates, &b09; becomes active again and resumes execution at the +statement following the SHELL statement. +</para> +<para> +Here are a few examples of using the shell from &b09;: + +<informalexample> +<programlisting> +SHELL "copy file1 file2" sequential execution + +SHELL "copy file1 file2&" concurrent execution + +SHELL "edit document" calling text editor + +SHELL "asm source o=obj ! spool &" concurrent assembly + +N:=5 +SHELL "kill "+STR$(N) + +file$ := "/d1/batch_jobs" concurrent execution of a +SHELL file$ + " -p >/p &" batch procedure file +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>END Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>END [<output list>]</command> +</cmdsynopsis> +This statement +ends execution of the procedure and returns to the calling procedure, +or to &b09; command mode if it was the highest level procedure. If an +output list is given, it also works the same as the PRINT statement. +END is an executable statement and can be used several times in the same +procedure. END is optional: it is not required at the "bottom" of a procedure. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +END + +END "I have finished execution" +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>Stop Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>STOP [<output list>]</command> +</cmdsynopsis> +This statement +immediately terminates execution of all procedures and returns to the +command mode. If an output list is given it also works like a +PRINT statement. +</para></sect2> +<sect2><title>BYE Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>BYE</command> +</cmdsynopsis> + +This statement +ends execution of the procedure and terminates &b09;. Any open files +are closed, and any unsaved procedures or data in the workspace will be lost. +This command is especially useful for creating PACKed programs and/or +programs to be called from OS-9 procedure files. +<warning> +<para> +This command causes &b09; to abort. +It should only be used if the program has been saved before it is tested! +</para> +</warning> +</para></sect2> +<sect2><title>ERROR Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>ERROR(<integer expr>)</command> +</cmdsynopsis> +This statement +generates an error having the error code specified by the result of +evaluation of the expression. ERROR is often used for testing error routines. +For details on error handling see the ON ERROR GOTO statement description. +</para></sect2> +<sect2><title>PAUSE Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>PAUSE [<output list>]</command> +</cmdsynopsis> +PAUSE suspends execution of the procedure and causes &b09; to enter +Debug Mode. If an output list is given it also works like a PRINT +statement. +<programlisting> +<output> BREAK IN PROCEDURE <procedure name> +</programlisting> +The Debug Mode "CONT" command can be used to resume procedure +execution at the following statement. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +PAUSE + +PAUSE "now outside main loop" +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>CHD and CHX Statements</title> +<para> +Syntax: +<cmdsynopsis> +<command>CHD <str expr></command> +<sbr> +<command>CHX <str expr></command> +</cmdsynopsis> +These statements +change the current default Data or Execution directory, +respectively. The string must specify the pathlist of a file +which has the DIR attribute. +For more information on the OS-9 directory structure, consult +the OS-9 User's Guide. +</para></sect2> +<sect2><title>DEG and RAD Statements</title> +<para> +Syntax: +<cmdsynopsis> +<command>DEG</command> +<sbr> +<command>RAD</command> +</cmdsynopsis> +These statements +set the procedure's state flag to assume angles stated in +degrees or radians in SIN, COS, TAN, ACS, ASN, and ATN functions. +This flag applies only to the currently active procedure. The default state +is radians. +</para></sect2> +<sect2><title>BASE 0 and BASE 1 Statements</title> +<para> +Syntax: +<cmdsynopsis> +<command>BASE 0</command> +<sbr> +<command>BASE 1</command> +</cmdsynopsis> + +These statements indicate whether a particular procedure's lowest array +or data structure index (subscript) is zero or one. The +default is one. These statements do not affect the string operations +(e.g., MID$, RIGHT$, OR LEFT$) where the beginning character of a string +is always index one. +</para></sect2> +<sect2><title>TRON and TROFF Statements</title> +<para> +Syntax: +<cmdsynopsis> +<command>TRON</command> +<sbr> +<command>TROFF</command> +</cmdsynopsis> +These statements turn the trace mode on or off, and are useful for debugging. +When trace mode is turned on, each statement is decompiled and printed +before execution. Also, the result of each expression evaluation is printed as +it occurs. +</para></sect2> +<sect2><title>Comment Statements</title> +<para> +Syntax: +<cmdsynopsis> +<command>REM <chars></command> +<sbr> +<command>(* <chars> [ *) ]</command> +</cmdsynopsis> +These statements are used to put comments in programs. The second form +of the statement is for compatibility with PASCAL programs. Comments +are retained in the I-code but are removed by the PACK compile command. +The "!" character can be typed in place of the keyword +REM when editing programs. The compiler trims away extra spaces +following REM to conserve memory space. +</para> +<para> +Examples: +<informalexample> +<programlisting> +REM this is a comment + +(* This is also a comment *) + +(* This is another kind of comment +</programlisting> +</informalexample> +</para></sect2></sect1> +<sect1><title>Declarative Statements</title> +<para> +The DIM, PARAM, and TYPE statements are called +<emphasis>declarative statements</emphasis> because +they are used to define and/or declare variables, arrays, and complex data +structures. The DIM and PARAM statements +are almost identical, the difference being that DIM are used to +declare storage used exclusively within the procedure, and the PARAM statement +is used to declare variables <emphasis>received</emphasis> from another calling procedure. +</para> +<para> +When do you need to use the DIM statement? +You don't need to for simple variables of type REAL because +this is the default format for undeclared variables. You also don't need to +for 32-character STRING type variables (any name ending with a +"$" is automatically assigned this type). Even though you don't have to +declare variables in these two cases, you may want to anyway to +improve your program's internal documentation. Those +things you <emphasis>must</emphasis> declare are: +<orderedlist numeration="arabic"> +<listitem> +<para>Any simple variables of type BYTE, INTEGER, or BOOLEAN.</para> +</listitem> +<listitem> +<para>Any simple STRING variables shorter or longer than 32 characters.</para> +</listitem> +<listitem> +<para>Arrays of any type.</para> +</listitem> +<listitem> +<para>Complex data structures of any type.</para> +</listitem> +</orderedlist> +</para> +<para> +The TYPE statement does not really create variable storage. Its purpose is to +describe a <emphasis>new</emphasis> data structure type that can be used +in DIM or PARAM statements in addition to the five atomic data +types built-in to &b09;. +Therefore, TYPE is only used in programs that use complex data structures. +</para> +<sect2><title>DIM Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>DIM <decl seq> {; <decl seq>}</command> +<sbr> +<command><decl seq> := <decl> {, <decl>} : <type>}</command> +<sbr> +<command><decl> := <name> [, <subscript> ]</command> +<sbr> +<command><subscr> := ( <const> [,<const> [,<const>]] )</command> +<sbr> +<command><type> := BYTE | INTEGER | REAL | BOOLEAN | + STRING | STRING <max len> | <user defined type></command> +<sbr> +<command><user def> := user defined by TYPE statement</command> +</cmdsynopsis> +The DIM statement is used to declare simple variables, +arrays, or complex data structures of the five +atomic types or any user-defined type. During compilation, &b09; assigns +storage required for all variables declared in DIM statements. +</para> +<sect3><title>Declaring Simple Variables</title> +<para> +Simple variables are declared by using the variable name in a DIM +statement without a subscript. If variables are not explicitly declared, they +are automatically assumed to be REAL, or tpe STRING[32] +if the variable name ends with a +"$" character. Therefore all simple variables of other types +must be explicitly declared. For example: + +<informalexample> +<programlisting> +DIM logical:BOOLEAN +</programlisting> +</informalexample> + +Several variables can be declared in sequence with a :<type> +following a group of the same type: +<informalexample> +<programlisting> +DIM a,b,c: STRING +</programlisting> +</informalexample> +In addition, several different types can be declared in a single DIM +statement by using a semicolon ";" to separate different types: + +<informalexample> +<programlisting> +DIM a,b,c:INTEGER; n,m:decimal; x,y,z:BOOLEAN +</programlisting> +</informalexample> + +In this example a, b, and c are type INTEGER, n and m are type "decimal" (a +user-defined type), and x, y, and z are type BOOLEAN. +String variables are declared the same way except an optional +maximum string length can be specified. If a length is not explicitly +given, 32 characters are assumed: + +<informalexample> +<programlisting> +DIM name:STRING[40]; address,city:STRING; zip:REAL +</programlisting> +</informalexample> + +In this case, "name" is a string variable of 40 characters maximum, "address" +and "city" are string variables of 32 characters each, and "zip" is a +real variable. +</para></sect3> +<sect3><title>Array Declarations</title> +<para> +Arrays can have one, two, or three dimensions. The DIM statement format +(including type grouping) +is the same as for simple variables except each name is followed by +subscript(s) to indicate its size. The maximum subscript size is +32767. Simple variable and array declarations can be mixed +in the same DIM statement: + +<informalexample> +<programlisting> +DIM a(10),b(20,30),c:INTEGER; x(5,5,5):STRING[12] +</programlisting> +</informalexample> + +In the example above, "a" is an array of 10 integers, "b" is a 20 by 30 +matrix of integers, "c" is a simple integer variable, and "x" is a +three-dimensional array of 12-character strings. +</para> +<para> +Arrays can be any atomic or user-defined type. By declaring arrays of +user-defined types, structures of arbitrary complexity and shape can +be generated. +Here's an example declaration that generates a doubly-linked list +of character strings. Each element of the array consists of the string +containing the data and two integer "pointers". + +<informalexample> +<programlisting> +TYPE link_pointers = fwd,back: INTEGER +TYPE element = data: STRING[64]; ptr: link_pointers +DIM list(100): element + +(* make a circular list *) +BASE0 +FOR index := 0 TO 99 + list(index).data := "secret message " + STR$(index) + list(index).ptr.fwd := index+1 + list(index).ptr.back := index1 +NEXT index +(* fix the ends *) +list(0).ptr.back := 99 +list(99).ptr.fwd := 0 + +(* Print the list *) +index=0 +REPEAT + PRINT list(index).data + index := list(index).ptr.fwd +UNTIL index=0 +END +</programlisting> +</informalexample> +</para></sect3></sect2> +<sect2><title>PARAM Statement</title> +<para> +Syntax: Same as DIM statement +</para> +<para> +PARAM is identical to the DIM statement, but it does not create +variable storage. Instead, it describes what parameters the "called" procedure +expects to receive from the "calling" procedure. +</para> +<para> +The programmer must insure that the total size of each +parameter (as evaluated by the RUN statement in the calling procedure) +conforms to the +amount of storage expected for each parameter in the called procedure as +specified by the PARAM statement. +&b09; checks the size of each parameter (to prevent +accidental access to storage other than the parameter) +but DOES NOT CHECK TYPE. However, in most cases the programmer +should ensure that the parameters evaluated in the RUN statement and +sent to the called procedure agree exactly with the PARAM statement +specification with respect to: the number of parameters, their order, size, +shape, and type. +</para> +<para> +Because type-checking is not performed, if you really know what you are +doing you can make the parameter passing operation perform useful but +normally illegal type conversions of identically-sized data structures. For +example, passing a string of 80 characters to a procedure expecting a +BYTE array having 80 elements assigns the numeric value of each +character in the string to the corresponding element of the byte array. +</para></sect2> +<sect2><title>TYPE Statement</title> +<para> +Syntax: + +<cmdsynopsis> +<command>TYPE <type decl> {; <type decl>}</command> +<sbr> +<command><type decl> := <field name> . <decl> : <type>}</command> +<sbr> +<command><decl> := <name> [, <subscript> ]</command> +<sbr> +<command><subscript> := ( <const> [,<const> [,<const>]] )</command> +<sbr> +<command><type> := BYTE | INTEGER | REAL | BOOLEAN | + STRING | STRING [<max len>] | <user defined></command> +<sbr> +<command><user defined> := user defined by TYPE statement</command> +</cmdsynopsis> + +This statement is used to define new data types. New data types are +defined as a "vector" (a one-dimensional array) of previously +defined types. This structure differs from an array in that the +various elements may be of different types, and the elements are +accessed by field name instead of an array index. +Here's an example: +<informalexample> +<programlisting> +TYPE cust_recd := name,address(3):STRING; balance +</programlisting> +</informalexample> + +This example creates a new data type called "cust_recd" which has three +named fields: a field called "name" which is a string, a field +called "address" which is a vector of three strings; and +a field called "balance" which is a (default) REAL value +</para> +<para> +The TYPE statement can include previously-defined types so very +complex non-rectangular data structures can be created such as +lists, trees, etc. This statement does not create any variable storage +itself; the storage is created when the newly-defined type is used in a +DIM statement. +The example show below creates an array having 250 elements of type +"cust_recd" that was defined above: + +<programlisting> +DIM customer_file(250):cust_recd +</programlisting> +To access elements of the array in assignment statements, the field name +is used as well as the index: +<programlisting> +name$ = customer_file(35).name +customer_file(N+1).address(3) = "New York, NY" +customer_file(X).balance= 125.98 +</programlisting> + +The complex structure allows creation of data types appropriate to +the job at hand by providing more natural organization and +association of data. Additionally, the position of the desired +element is known and defined at compilation-time and need not be +calculated at run time, unlike arrays, and can therefore be accessed +faster than arrays. +</para> +</sect2></sect1> +</chapter> + + +<chapter> +<title>Input and Output Operations</title> + + +<sect1><title>Files and Unified Input/Output</title> +<para> +A file is a logical concept for a sequence of data which is +saved for convenience in use and storage. File data may be pure +binary data, textual data (ASCII characters), or any other useful +information. Hardware input/output ("I/O") devices used by OS-9 +also work like files, so you can generally use any I/O facility +regardless of whether you are +working with disk files or I/O devices such as printers. This single +interface standard for any device and simple communication facilities allow +any device to be used with any other device. This concept is known as +"unified I/O". Note that +unified I/O can benefit routine programming. For example: +file operations can be debugged by communicating with a terminal or +printer instead of a storage device, and procedures which normally +communicate with a terminal can be tested with data coming from and sent +to a storage device. +</para> +<para> +&b09; normally works with two types of files: +sequential files and random-access files. +</para> +<para> +A sequential file sends or receives (WRITE/READ) textual data only in +order. It is not generally possible to start over at the beginning of +a sequential file once a number of bytes have been accessed (many I/O +devices such as printers are necessarily sequential). A sequential +file contains only valid ASCII characters; the READ and WRITE commands +perform format conversion similar to that done automatically in INPUT and +PRINT commands. A sequential file contains record-delimiter characters +(carriage return) which separate the data created by different WRITE +operations. Each WRITE command will send a complete sequential-file +record, which is an arbitrary number of characters terminated by a +carriage return. Each READ reads all characters up to the next carriage +return. +</para> +<para> +A random-access file sends and receives (PUT/GET) data in binary form +exactly as it is internally represented in &b09;. This minimizes both the +time involved in converting the data to and from ASCII representation, +as well as reducing the file space required to store the data. It is +possible to PUT and GET individual bytes, or a substructure of many +bytes (in a complex structure). The GET structure statement merely +recovers the number of bytes associated with that type of structure. +It is possible to move to a particular byte in a random-access file +(using SEEK) and to begin to PUT or GET sequentially from that point (in +general, "SEEK #path,0" is equivalent to the REWIND used in some forms +of BASIC). Since the random-access file contains no record-separators +to indicate the size of particular elements of the file, the programmer +should use the SIZE function to determine the size of a single element, +then use SEEK to move to the desired element within the file. +</para> +<para> +A new file is made on a storage device by executing CREATE. Once a file +exists, the OPEN command is used to notify the operating system to set up +a channel to the desired device and return that path number to the &b09; +program. This channel number is then used in file-access operations (e.g., +READ, WRITE, GET, PUT, SEEK, etc.). When the programmer is finished with +the file, it should be terminated by CLOSE to assure that the file system +has updated all data back onto magnetic media. +</para></sect1> +<sect1><title>I/O Paths</title> +<para> +A "path" is a description of a "channel" through which data flows from a +given program outward or from some device inward. In order for data to +flow to or from a device, there must be an associated OS-9 device driver +— see the OS9 Users Manual. When a path is created, OS-9 returns +a unique number to identify the path in subsequent file operations. This +"path number" is used by the I/O statements to specify the file to be +used. Three path numbers have special meanings because they are "standard +I/O paths" representing &b09;'s interactive input/output (your terminal). +These are automatically "opened" for you and should not be closed except +in very special circumstances. The standard I/O path numbers are: +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="0.3in"> +<tbody> +<row> +<entry>0</entry> +<entry>Standard Input (Keyboard)</entry> +</row> +<row> +<entry>1</entry> +<entry>Standard Output (Display)</entry> +</row> +<row> +<entry>2</entry> +<entry>Standard Error/Status (Display)</entry> +</row> +</tbody> +</tgroup> +</informaltable> +</para> +<para> +The table below is a summary of the I/O statements within &b09; and their +general usage. This reflects typical usage; most statements can be used +with any I/O device or file. Sometimes certain statements are used in +unusual ways by advanced programmers to achieve certain special effects. +<informaltable frame="none"> +<tgroup cols="3"> +<colspec colwidth="0.8in"> +<thead> +<row> +<entry>Statement</entry> +<entry>Generally Used With</entry> +<entry>Data Format (File Type)</entry> +</row> +</thead> +<tbody> +<row> +<entry>INPUT</entry> +<entry>Keyboard (interactive input)</entry> +<entry>Text (Sequential)</entry> +</row> +<row> +<entry>PRINT</entry> +<entry>Terminals, Printers</entry> +<entry>Text (Sequential)</entry> +</row> +<row> +<entry>OPEN</entry> +<entry>Disk Files and I/O Devices</entry> +<entry>Any</entry> +</row> +<row> +<entry>CREATE</entry> +<entry>Disk Files and I/O Devices</entry> +<entry>Any</entry> +</row> +<row> +<entry>CLOSE</entry> +<entry>Disk Files and I/O Devices</entry> +<entry>Any</entry> +</row> +<row> +<entry>DELETE</entry> +<entry>Disk Files</entry> +<entry>Any</entry> +</row> +<row> +<entry>SEEK</entry> +<entry>Disk Files</entry> +<entry>Binary (Random)</entry> +</row> +<row> +<entry>READ</entry> +<entry>Disk Files</entry> +<entry>Text (Sequential)</entry> +</row> +<row> +<entry>WRITE</entry> +<entry>Disk Files</entry> +<entry>Text (Sequential)</entry> +</row> +<row> +<entry>GET</entry> +<entry>Disk Files and I/O Devices</entry> +<entry>Binary (Random)</entry> +</row> +<row> +<entry>PUT</entry> +<entry>Disk Files and I/O Devices</entry> +<entry>Binary (Random)</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +</para> +<sect2><title>INPUT Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>INPUT [#<int expr>,] ["<prompt>",] <input list></command> +</cmdsynopsis> +This statement accepts input during the execution of a program. The +input is normally read from the standard input device (terminal) +unless an optional path number is given. When the INPUT statement +is encountered, program execution is suspended and a "?" prompt is +displayed. If the optional prompt string is given, it is displayed +instead of the normal "?" prompt. This means that the INPUT statement +is really <emphasis>both</emphasis> +an input and outout statement. Therefore, if a path other than the +default standard input path is used, the path should be open in UPDATE +mode. This makes INPUT dangerous if used on disk files, unless you like +prompts in your data (use READ). +</para> +<para> +The data entered is assigned in order to the variable names in the order +they appear in the input list. The variables can be of any atomic type, +and the input data must be of the same (or compatible) type. The line +is terminated by a carriage return. There must be at least as many input +items given as variables in the input list. The length of the input line +cannot exceed 256 characters. +</para> +<para> +If any error occurs (type mismatch, insufficient amount of data, etc.), +the message: +<screen> +**INPUT ERROR RETYPE** +</screen> +is displayed, followed by a new prompt. The entire input line must +then be reentered. +</para> +<para> +The INPUT statement +uses OS-9's line input function (READLN) which performs line +editing such as backspace, delete, end-of-file, etc. To perform input +WITHOUT editing (i.e., to read pure binary data), use the GET statement. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +INPUT number,name$,location + +INPUT #14, "What is your selection", choice + +INPUT "What's your name? ",name$ +</programlisting> +</informalexample> +Here's how to read a single character (without editing) from the terminal +(path #0): +<informalexample> +<programlisting> +DIM char:STRING[1] +GET #0,char +</programlisting> +</informalexample> +For a function to test if data is available from the keyboard without +"hanging" the program, see the "INKEY" assembly language program included +in Appendix A. +</para></sect2> +<sect2><title>PRINT Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>PRINT <output list></command> +<sbr> +<command>PRINT #<int expr>, <output list></command> +<sbr> +<command>PRINT USING <str expr>, <output list></command> +<sbr> +<command>PRINT #<int expr>, USING <str expr>, <output list></command> +</cmdsynopsis> +This statement outputs the values of the items given in the output list +to the standard output device (path #1, the terminal) unless another +path number is specified. +</para> +<para> +The output list consists of one or more items separated by commas or +semicolon characters. Each item can be a constant, variable, or expression +of any atomic type. The PRINT statement evaluates each item and converts +the result to corresponding ASCII characters which are then displayed. +If the separator character following the item is a semicolon, the +next item will be displayed without any spacing in between. If a comma +is used, spaces are output so the next item starts at the next "tab" +zone. The tab zones are 16 characters long starting at the beginning of +the line. If the line is terminated by a semicolon, the usual carriage +return following the output line is inhibited. +</para> +<para> +The "TAB(expr)" function can be used as an item in the output list, which +outputs the correct number of spaces to cause the next item to start +in the print column specified by the result of the expression. If the +output line is already past the desired tab position, the TAB is ignored. +A related function, "POS", can be used in the program to determine +the output position at any given time. The output columns are numbered +from one to a maximum of 255. The size of &b09;'s output buffer varies +according to stack size at the moment. A prectical values is at least +512 characters. +</para> +<para> +The PRINT USING form of this statement is described at the end of +this chapter. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +PRINT value,temp+(n/2.5),location$ + +PRINT #printer_path,"The result is "; n + +PRINT "what is " + name$ + "'s age? "; + +PRINT "index: ";i;TAB(25);"value: ";value + +PRINT USING "R10.2,X2,R5.3",x,y + +PRINT #outpath USING fmt$,count,value + +(* print an 80character line of all dashes *) +REPEAT + PRINT ""; +UNTIL POS >= 80 +PRINT +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>OPEN Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>OPEN #<int var>,"<str expr>" [ : <access mode> ]</command> +<sbr> +<command><access mode> := <mode> ! <mode> + <access mode></command> +<sbr> +<command><mode> := READ ! WRITE ! UPDATE ! EXEC ! DIR</command> +</cmdsynopsis> +This statement issues a request to OS-9 to open an I/O path to an existing +file or device. The STRING expression is evaluated and passed to OS-9 as +the descriptive pathlist.The variable name specified must be DIMensioned +as type INTEGER or BYTE and is used "receive" the "path number" assigned +to the path by OS-9. This path number is used to reference the specific +file/device in subsequent input/output statements. +</para> +<para> +The OPEN statement may also specify the path's desired "access mode" which +can be READ, WRITE, UPDATE, EXEC, or DIR. This defines which direction I/O +transfers will occur. If no access mode is specified, UPDATE is assumed +and both reading and writing are permitted. The DIR mode allows OS-9 +directory type-files to be accessed but should NOT be used in combination +with WRITE or UPDATE modes. The EXEC mode causes the current execution +directory to be used instead of the current data directory. Refer to the +"OS-9 User's Guide" for more information on how files access modes. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +DIM printer_path:BYTE; name:STRING[24] +name="/p" +OPEN #printer_path,name:WRITE +PRINT #printer_path,"Mary had a little lamb" +CLOSE #printer_path + +DIM inpath:INTEGER +dev$="/winchester/" +INPUT name$ +OPEN #inpath,dev$+name$:READ + +OPEN #path:userdir$:READ+DIR + +OPEN #path,name$:WRITE+EXEC +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>CREATE Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>CREATE #<int var>,"<str expr>" [ : <access mode> ]</command> +<sbr> +<command><access mode> := <mode> ! <mode> + <access mode></command> +<sbr> +<command><mode> := WRITE ! UPDATE ! EXEC</command> +</cmdsynopsis> +The CREATE statement is used to create a new file on a multifile mass storage +device such as disk or tape. If the device is not of multifile type, +this statement works like an "OPEN" statement. +The variable name is used to receive the path number assigned by +OS-9 and must be of BYTE or INTEGER type. The STRING expression is +evaluated and passed to OS-9 to be used as the descriptive pathlist. +</para> +<para> +The "access mode" defines the direction of subsequent I/O transfers and +should be either WRITE or UPDATE. "UPDATE" mode allows the file to be +either read or written. +</para> +<para> +OS-9 has a single file type that can be accessed both sequentially OR at +random. Files are byte-addressed, so no explicit "record" length need be +given (see GET and PUT statements). When a new file is created, it has an +initial length of zero. Files are expanded automatically by PRINT, WRITE, +or PUT statements that write beyond the current "end of file". +File size may be set explicitly using the OS9 statement. +</para> +<para> +Examples: +<informalexample> +<programlisting> +CREATE #trans,"transactions":UPDATE + +CREATE #spool,"/user4/report":WRITE + +CREATE #outpath,name$:UPDATE+EXEC +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>Close Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>CLOSE #<int expr> {,#<int expr>}</command> +</cmdsynopsis> +The CLOSE statement notifies OS-9 that one or more I/O paths are no longer +needed. The paths are specified by their number(s). If the path closed +used a non-sharable device (such as a printer), the device is released +and can be assigned to another user. The path must have been previously +established by means of the OPEN or CREATE statements. +</para> +<para> +Paths #0, #1, and #2 (the standard I/O paths) should never be closed +unless the user immediately opens a new path to take over the Standard +Path number. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +CLOSE #master,#trans,#new_master + +CLOSE #5,#6,#9 + +CLOSE #1 \(* closes standard output path *) +OPEN #path,"/T1" \(* Permanently redirects Std Output *) + +CLOSE #0 \(* closes standard input path *) +OPEN #path,"/TERM" \(* Permanently redirects Std Input *) +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>DELETE Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>DELETE <str expr></command> +</cmdsynopsis> +This statement is used to delete a mass storage file. The file's name +is removed from the directory and all its storage is deallocated, so any +data on the file is permanently lost. The string expression is evaluated +and passed to OS-9 as the descriptive pathlist of the file. +</para> +<para> +The user must have write permission for the file to be deleted. See +the "OS-9 User's Guide" for more information. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +DELETE "/D0/old_junk" + +name$="file55" +DELETE name$ +DELETE "/D2/"+name$ (deletes file named "/D2/file55") +</programlisting> +</informalexample> + + +</para></sect2> +<sect2><title>SEEK Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>SEEK #<int expr num>,<real expr></command> +</cmdsynopsis> +SEEK changes the file pointer address of a mass storage file, +which is the address of the next data byte(s) that are to be read or +written next. Therefore, this statement is essential for random access +of data on files using the GET and PUT statements. +</para> +<para> +The first expression specifies the path number of +the file and must evaluate to a byte value. The second expression specifies +the desired file pointer address, and must evaluate to a REAL +value in the range 0 <= result <= 2,147,483,648. Any fractional +part of the result is truncated. Of course, the actual maximum file size +depends on the capacity of the device. +</para> +<para> +Although SEEK is normally used with random-access files, it can be used +to "rewind" sequential files. For example: + +<programlisting> +SEEK #path,0 +</programlisting> +is the same as a "rewind" or "restore" function. This is the only form of +the SEEK statement that is generally useful for files accessed by READ +and WRITE statements. These statements use variable-length records, so +it is difficult to know the address of any particular record in the file. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +SEEK #fileone,filptr*2 + +SEEK #outfile,208894 + +SEEK #inventory,(part_num 1) * SIZE(inv_rcd) +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>WRITE Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>WRITE #<int expr>,<output list></command> +</cmdsynopsis> +This statement writes data in ASCII character format on a file/device. The +first expression specifies the number of a path that was previously +opened by a OPEN or CREATE statement in WRITE or UPDATE mode. +</para> +<para> +The output list consists of one or more expressions separated by commas. +Each expression can evaluate to any expression type. The result is then +converted to an ASCII character string and written on the specified path +beginning at the present file pointer which is updated as data is written. +</para> +<para> +If the output list has more than one item, ASCII null characters ($00) +are written between each output string. The last item is followed by a +carriage return character. +</para> +<para> +Note that this statement creates variable-length ASCII records. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +WRITE #outpath,cat,dog,mouse + +WRITE #xfile,LEFT$(A$,n),count/2 +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>READ Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>READ #<int expr num>,<input list></command> +</cmdsynopsis> +This statement causes input data in ASCII character format to be read +from a file or device. The first expression specifies a path number. +The path number which must have been previously opened by an OPEN or CREATE +statement in READ or UPDATE access mode (except the standard input path #0). +Data is read starting at the path's current file pointer address which +is updated as data is read. +</para> +<para> +This statement calls OS-9 to read a variable length ASCII +record. Individual data items within the record are converted to &b09;'s +internal binary format. These results are assigned in order to the +variables given in the input list. The input data must match the +number and type of the variables in the input list. +</para> +<para> +The individual data items in the input record are separated by ASCII +null characters. Numeric items can also be delimited by commas or space +characters. The input record is terminated by a carriage return character. +</para> +<para> +Examples: + +<informalexample> +<programlisting> +READ #inpath,name$,address$,city$,state$,zip + +PRINT #1,"height,weight? " +READ #0,height,weight +</programlisting> +</informalexample> + +<note> +<para> +READ is also used to read lists of expressions in the program. +See the DATA statement section for details. +</para> +</note> +</para></sect2> +<sect2><title>GET/PUT Statement</title> +<para> +Syntax: +<cmdsynopsis> +<command>GET #<expr>,<struct name></command> +<sbr> +<command>PUT #<expr>,<struct name></command> +</cmdsynopsis> +The GET and PUT statements read and write fixed-size binary data records +to files or devices. These are the primary I/O statements +used for random access input and output. +</para> +<para> +The first expression is evaluated and used as the number of the +I/O path which must have previously been opened by an OPEN or CREATE +statement. Paths used by PUT statements must have been opened in WRITE +or UPDATE access modes, and paths used by GET statements must be in READ +or UPDATE mode. +</para> +<para> +The statement uses exactly one name which can be the name of a variable, +array, or complex data structure. Data is written from, or read into, the +variable or structure named. The data is transferred in &b09;'s internal +binary format without conversion which affords very high throughput +compared to READ and WRITE statements. Data is transferred beginning +at the current position of the path's file pointer (see SEEK statement) +which is automatically updated. +</para> +<para> +OS-9's file system does not inherently impose record structures on +random-access files. All files are considered to be continuous sequences of +addressable binary bytes. A byte or group of bytes located anywhere in the +file can be read or written in any order. Therefore the +<emphasis>programmer</emphasis> is free to use the basic file access +system to create any record structure desired. +</para> +<para> +Record I/O in &b09; is associated with data structures defined by DIM +and TYPE statements. The GET and PUT statements write entire data +structures or parts of data structures. A PUT statement, for example, +can write a simple variable, an entire array, or a complex data structure +in one operation. To illustrate how this works, here is an example +based on a simple inventory system that requires a random access file +having 100 records. Each record must include the following information: +the name of the item (a 25-byte character string), the item's list price +and cost (both real numbers), and the quantity on hand (an integer). +</para> +<para> +First it is necesary to use the TYPE statement to define a new +data type that describes such a record. For example: +<informalexample> +<programlisting> +TYPE inv_item=name:STRING[25];list,cost:REAL;qty:INTEGER +</programlisting> +</informalexample> +This statement describes a new record type called "inv_item" but does not +cause variable storage to be assigned for it. The next step is to create +two data structures: an array of 100 "records" of type "inv_item" to be called +"inv_array" and a single working record called "work_rec": +<programlisting> +DIM inv_array(100):inv_item +DIM work_rec:inv_item +</programlisting> +You can manually count the number of bytes assigned for each type to +calculate the total size of each record. Sometimes these can become +complicated and error-prone. Also, any change in a TYPE definition +could require recalculation. Fortunately, &b09; has a built-in +function: + +<programlisting> +SIZE(<name>) +</programlisting> +that returns the number of bytes assigned to any variable, array, or +complex data structure. In our example, SIZE(work_rec) will return the number +37, and SIZE(inv_array) will return 3700. The size function is often +used in conjunction with the SEEK statement to position a file pointer +to a specific record's address. +</para> +<para> +The procedure below creates a file called "inventory" and initializes it +with zeroes and nulls: + +<programlisting> +PROCEDURE makefile +TYPE inv_item = name:STRING[25]; list,cost:REAL; qty:INTEGER +DIM inv_array(100):inv_item +DIM work_rec:inv_item +DIM path:byte +CREATE #path,"inventory" +work_rec.name = "" +work_rec.list := 0. +work_rec.cost := 0. +work_rec.qty := 0 +FOR n = 1 TO 100 + PUT #path,work_rec +NEXT n +END +</programlisting> + +Notice that the assignment statements referenced each named "field" of +work_rec by name, but PUT referenced the record as a whole. +</para> +<para> +The subroutine below asks for a record number, then asks for data, and +writes it in the file at the specified record: + +<programlisting> +INPUT "Record number ?",recnum +INPUT "Item name? ",work_rec.name +INPUT "List price? ",work_rec.list +INPUT "Cost price? ",work_rec.cost +INPUT "Quantity? ",work_rec.qty +SEEK #path, (recnum 1) * SIZE(work_rec) +PUT #path,work_rec +</programlisting> +This routine below uses a loop to read the entire file into the array +"inv_array": + +<programlisting> +SEEK #path,0 \ (* "rewind" the file *) +FOR k = 1 TO 100 + GET #path,inv_array(k) +NEXT k +</programlisting> + +Because ENTIRE STRUCTURES can be read, we can eliminate the FOR/NEXT +loop and do exactly the same thing by: + +<programlisting> +SEEK #path,0 +GET #path,inv_array +</programlisting> + +The above example is a very simple case, but it illustrates the combined +power of &b09; complex data structures and the random access I/O +statements. When fully exploited, this system has the following important +characteristics: +<orderedlist numeration="arabic"> +<listitem> +<para> +It is self-documenting. You can clearly see what a program does because +structures have descriptive, named sub-structures. +</para> +</listitem> + +<listitem> +<para> +It is extremely fast. +</para> +</listitem> + +<listitem> +<para> +Programs are simplified and require fewer statements to perform I/O +functions than in other BASICs. +</para> +</listitem> + +<listitem> +<para> +It is versatile. By creating appropriate data structures you can read +or write almost any kind of data in any file, including files created by +other programs or languages. +</para> +</listitem> +</orderedlist> + +These advantages are possible because a single GET or PUT statement can +move any amount of data, organized any way you want. +</para></sect2></sect1> +<sect1><title>Internal Data Statements</title> +<sect2><title>DATA/READ/RESTORE Statements</title> +<para> +Syntax: +<cmdsynopsis> +<command>READ <input list></command> +<sbr> +<command>DATA <expr> , { <expr> }</command> +<sbr> +<command>RESTORE [ <line number> ]</command> +</cmdsynopsis> +These statements provide an efficient way to build constant tables +within a program. DATA statements provide values, the READ statement +assign the values to variables, and RESTORE statements can be used to +set which data statement is to be read next. +</para> +<para> +The DATA statements have one or more expressions separated by commas. +They can be located anywhere in a program. The expressions are evaluated +each time the data statements are read and can evaluate to any type. +Here are some examples: +<informalexample> +<programlisting> +DATA 1.1,1.5,9999,"CAT","DOG" +DATA SIN(temp/25), COS(temp*PI) +DATA TRUE,FALSE,TRUE,TRUE,FALSE +</programlisting> +</informalexample> +</para> +<para> +The READ statement has a list of one or more variable names. When +executed, it gets "input" by evaluating the current expression in the +current data statement. The result must match the type of the variable. When +all the expressions in a DATA statement have been evaluated, the next +DATA statement (in sequential order) is used. If there are no more DATA +statements following, processing "wraps around" to the first data statement +in the program. +</para> +<para> +The RESTORE statement used without a line number causes the first DATA +statement in the program to be used next. If it is used with a line +number, the data statement having that line number is used next. +</para> +<para> +Examples: +<informalexample> +<programlisting> + DATA 1,2,3,4 + DATA 5,6,7,8 +100 DATA 9,10,11,12 + FOR N := 1 TO X + READ ARRAY(N) + NEXT N + RESTORE 100 + READ A,B,C,D +</programlisting> +</informalexample> +</para></sect2></sect1> +<sect1><title>Formatted Output: The Print Using Statement</title> +<para> +&b09; has a powerful output editing capability useful for report generation +and other applications where formatted output is required. The +output editing uses the PRINT USING statement which has the following +syntax: +<cmdsynopsis> +<command>PRINT [<expr#>,] USING <str expr> , <output list></command> +</cmdsynopsis> +The optional path number expression can be used to specify the path +number of any output file or device. If it is omitted, the output is +written to the standard output path (usually the terminal). +</para> +<para> +The string expression is evaluated and used as a "format specification" +which contains specific formatting directives for each item in the "output +list". The items in the output list can be constants, variables, or +expressions of any atomic type. BLANKS ARE NOT ALLOWED IN FORMAT STRINGS! +As each output item is processed, it is matched up with a specification +in the format list. The type of each expression result must be compatible +with the corresponding format specification. If there are fewer format +specifications than items in the output list, the format specification +list is repeated again from its beginning as many times as necessary. +</para> +<para> +A format string has one or more format specifications which are separated +by commas. There are two kinds of specifications: ones that control +output editing of an item from the output list, and ones that cause an +output function by themselves (such as tabbing and spacing). There are +six basic output editing directives. Each has a corresponding one-letter +identifier: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="0.6in"> +<tbody> +<row> +<entry>R</entry> +<entry>real format</entry> +</row> +<row> +<entry>E</entry> +<entry>exponential format</entry> +</row> +<row> +<entry>I</entry> +<entry>integer format</entry> +</row> +<row> +<entry>H</entry> +<entry>hexadecimal format</entry> +</row> +<row> +<entry>S</entry> +<entry>string format</entry> +</row> +<row> +<entry>B</entry> +<entry>boolean format</entry> +</row> +</tbody> +</tgroup> +</informaltable> +The identifier letter is followed by a constant number called the "field +width". This number indicates the exact number of print columns the +output is to occupy and must allow for the data AND "overhead" character +positions such as sign characters, decimal points, exponents, etc. +Some formats have additional mandatory or optional parameters that +control subfields or select editing options. One of these options is +"justification" which specifies whether the output is to "line up" on +the left, right side, or center of the output field. Fields are commonly +right-justified in reports because it arranges them into neat columns +with decimal points aligned in the same position. +</para> +<para> +The abbreviations and symbols used in the syntax specifications are: + +<informaltable frame="none"> +<tgroup cols="3"> +<colspec colwidth="0.4in"> +<tbody> +<row> +<entry>w</entry> +<entry>Total field width</entry> +<entry>1 <= w <= 255</entry> +</row> +<row> +<entry>f</entry> +<entry>Fraction field</entry> +<entry>1 <= w <= 9</entry> +</row> +<row> +<entry>j</entry> +<entry>OPTIONAL justification</entry> +<entry>< (left) > (right) ^ (center)</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +</para> +<sect2><title>Real Format</title> +<para> +Syntax: +<cmdsynopsis> +<command>Rw.fj</command> +</cmdsynopsis> +This format can be used for numbers of types REAL, INTEGER, or +BYTE. The total field width specification must include two overhead +positions for the sign and decimal point. The "f" specifies how many +fractional digits to the right of the decimal point are to be +displayed. If the number has more significant digits than the field +allows for, the undisplayed places are used to round the displayed digits. For +example: + +<programlisting> +PRINT USING "R8.2", 12.349 gives 12.35 +</programlisting> + +The justification modes are: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="0.3in"> +<tbody> +<row> +<entry><</entry> +<entry>Left justify with leading sign and trailing spaces. (default if +justification mode omitted)</entry> +</row> +<row> +<entry>></entry> +<entry>right justify with leading spaces and sign.</entry> +</row> +<row> +<entry>^</entry> +<entry>right justify with leading spaces and trailing sign +(financial format)</entry> +</row> +</tbody> +</tgroup> +</informaltable> + + +Examples: + +<informalexample> +<programlisting> +PRINT USING "R8.2<",5678.123 5678.12 +PRINT USING "R8.2>",12.3 12.30 +PRINT USING "R8.2<",555.9 555.90 +PRINT USING "10.2^",6722.4599 6722.46 +PRINT USING "R5.1","9999999" ***** +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>Exponential Format</title> +<para> +Syntax: +<cmdsynopsis> +<command>Ew.fj</command> +</cmdsynopsis> +This format prints numbers of types REAL, INTEGER, or BYTE +in the scientific notation format using a mantissa and decimal exponent. +The syntax and behavior of this format is similar to the REAL format +except the "w" field width must allow for eight overhead positions for the +mantissa sign, decimal point, and exponent characters. +The "<" and ">" justification modes are allowed and work the same way. +</para> +<para> +Example: + +<informalexample> +<programlisting> +PRINT USING "E12.3",1234.567 1.235E+03 + +PRINT USING "E12.6>",0.001234 1.234000E-3 +</programlisting> +</informalexample> + +</para></sect2> +<sect2><title>Integer Format</title> +<para> +Syntax: +<cmdsynopsis> +<command>Iwj</command> +</cmdsynopsis> +This format is used to display numbers of types INTEGER or BYTE, +and REAL numbers that are within range for automatic type conversion. +The "w" field width must allow for one position overhead for the sign. +The justification modes are: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="0.3in"> +<tbody> +<row> +<entry><</entry> +<entry>left justify with leading sign and trailing spaces (default)</entry> +</row> +<row> +<entry>></entry> +<entry>right justify with leading spaces and sign</entry> +</row> +<row> +<entry>^</entry> +<entry>right justify with leading spaces and zeroes</entry> +</row> +</tbody> +</tgroup> +</informaltable> +Example: +<informalexample> +<programlisting> +PRINT USING "I4<",10 10 + +PRINT USING "I4>",10 10 + +PRINT USING "I4^",10 010 +</programlisting> +</informalexample> + + +</para></sect2> +<sect2><title>Hexadecimal Format</title> +<para> +Syntax: +<cmdsynopsis> +<command>Hwj</command> +</cmdsynopsis> +This format can be used to display the internal binary representation +of ANY data type, using hexadecimal characters. The "w" field width +specification determines the number of hexadecimal characters to +output. Justification modes are: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="0.3in"> +<tbody> +<row> +<entry><</entry> +<entry>left justify with trailing spaces</entry> +</row> +<row> +<entry>></entry> +<entry>right justify, leading spaces</entry> +</row> +<row> +<entry>^</entry> +<entry>center justify</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +Because the number of bytes of memory used to represent data varies +according to type, the following specification make the most sense for +each data type: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="0.5in"> +<tbody> +<row> +<entry>H2</entry> +<entry>boolean, byte (one byte)</entry> +</row> +<row> +<entry>H4</entry> +<entry>integer (two bytes)</entry> +</row> +<row> +<entry>H10</entry> +<entry>real (five bytes)</entry> +</row> +<row> +<entry>Hn*2</entry> +<entry>string of length n</entry> +</row> +</tbody> +</tgroup> +</informaltable> + + +Examples: + +<informalexample> +<programlisting> +PRINT USING "H4",100 00C4 + +PRINT USING "H4",-1 FFFF + +PRINT USING "H10",1.5 01D0000000 + +PRINT USING "H8","ABC" 414243 +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>String Format</title> +<para> +Syntax: +<cmdsynopsis> +<command>Swj</command> +</cmdsynopsis> +This format is used to display string data of any length. The "w" field +width specifies the total field size. If the string to be displayed is +shorter than the field size, it is padded with spaces according to the +justification mode. If it is too long, it will be truncated on the right side. +The format specifications are: + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="0.3in"> +<tbody> +<row> +<entry><</entry> +<entry>Left justify (default if mode omitted)</entry> +</row> +<row> +<entry>></entry> +<entry>right justify</entry> +</row> +<row> +<entry>^</entry> +<entry>Center justify</entry> +</row> +</tbody> +</tgroup> +</informaltable> + +Examples: + +<informalexample> +<programlisting> +PRINT USING "S8<","HELLO" HELLO + +PRINT USING "S8>","HELLO" HELLO + +PRINT USING "S8^","HELLO" HELLO +</programlisting> +</informalexample> + + +</para></sect2> +<sect2><title>Boolean Format</title> +<para> +Syntax: +<cmdsynopsis> +<command>Bwj</command> +</cmdsynopsis> +This format is used to display boolean data. The result of the boolean +expression is converted to the strings "TRUE" and "FALSE". +The specification is otherwise identical to the STRING format. +</para></sect2> +<sect2><title>Control Specifications</title> +<para> +Control specifications are useful for horizontal formatting of the output +line. They are not matched with items in the output list and can be used +freely. The control formats are + +<informaltable frame="none"> +<tgroup cols="2"> +<colspec colwidth="0.5in"> +<tbody> +<row> +<entry>Tn</entry> +<entry>Tab to column n</entry> +</row> +<row> +<entry>Xn</entry> +<entry>Space n columns</entry> +</row> +<row> +<entry>'str'</entry> +<entry>Include constant string. The string must not include single or +double quotes, backslash or carriage return characters.</entry> +</row> +</tbody> +</tgroup> +</informaltable> +Warning: Control specifications at the end of the format +specification list will NOT be processed if all output items have +been exhausted. +</para> +<para> +Example + +<informalexample> +<programlisting> +PRINT USING "'addr',X2,H4,X2,'data',X2,H2",1000,100 prints + +addr 03E8 data C4 +</programlisting> +</informalexample> +</para></sect2> +<sect2><title>Repeat Groups</title> +<para> +Many times identical sequences of specifications are repeated in format +specification lists. The repeated groups can be enclosed in parentheses and +preceded by a repeat count. These repeat groups can be nested. +Here are some examples: + +<informalexample> +<programlisting> +"2(X2,R10.5)" is the same as "X2,R10.5,X2,R10.5" + +"2(I2,2(X1,S4))" is the same as "I2,X1,S4,X1,S4,I2,X1,S4,X1,S4" + </programlisting> + </informalexample> +</para> +</sect2> +</sect1> +</chapter> + +<chapter> +<title>Program Optimization</title> +<sect1><title>General Execution Performance of &b09;</title> +<para> +The &b09; multipass compiler produces a compressed and +optimized low-level "I-code" for execution. Compared to other BASIC +languages program storage is greatly decreased and execution speed +is increased. +</para> +<para> +High-level language interpreters have a general reputation for slowness +which is probably not deserved. Because the &b09; I-code is kept at +a powerful level, a single, fast I-code interpretation will so that +there is often result in many MPU instruction cycles (such as execution +of floating-point arithmetic operations). Thus, for complex programs +there is little performance difference between execution of I-code and +straight machine-language instructions. This is generally not the case +with traditional BASIC interpreters that have to "compile" from text as +they run or even "tokenized" BASICs that must perform table-searching +during execution. &b09; I-code instructions that reference variable +storage, statements, labels, etc., contain the actual memory addresses +so no table searching is ever required. Off course, &b09; fully exploits +the power of the 6809's instruction set which was optimized for efficient +execution of compiler-produced code. +</para> +<para> +Because the &b09; I-code is interpreted, a variety of entry-time +tests and run-time tests and development aids are available to help +in program development; aids not available on most compilers. +The editor reports errors immediately when they are entered, +the debugger allows debugging using the original program source +statements and names, and +the I-code interpreter performs run-time error checking of things such +as array bound errors, subroutine nesting, arithmetic errors, and other +errors that are not detected (and usually crash) native-compiler-generated +code. + +</para></sect1> +<sect1><title>Optimum Use of Numeric Data Types</title> +<para> +Because &b09; includes several different numeric representations +(i.e., REAL, INTEGER, and BYTE) and does "automatic type conversions" +between them, it is easy to write expressions or loops that take at +least ten times longer to execute than is necessary. Some particular +&b09; numeric operators (+, , *, /) and control structures (FOR..NEXT) +include versions for both REAL and INTEGER values. The INTEGER versions, +off course, are much faster and may have slightly different properties +(e.g., INTEGER divides discard any remainder). Type conversions takes +time so expressions whose operands and operators are of the same type +are more efficient. +</para> +<para> +&b09;'s REAL (floaing point) math package provides excellent +performance. A special 40-bit binary floating point representation +designed for speed and accuracy was developed especially for &b09; +after exhaustive research. The new CORDIC technique is used to derive +all transcendental functions (SIN, TAN, LOG, EXP, etc.). This integer +shit-and-add technique is faster and more consistantly accurate than +the commonly used series-expansion approximations. +</para> +<para> +Nonetheless, INTEGER operations are faster because they generally have +corresponding 6809 machine-language instructions. Overall program speed +will increase and storage requirements will decrease if INTEGERs are used +whenever possible. INTEGER arithmetic operations use the same symbols as +REAL but &b09; automatically selects the INTEGER operations when working +with an integer-value result. Only if all operands of an expression are +of types BYTE or INTEGER will the result also be INTEGER. +</para> +<para> +Sometimes, similar or identical results can be obtained in a number +of different ways at various execution speeds. For example, if the +variable "value" is an integer, then "value*2" will be a fast integer +operation. However, if the expression is "value*2.0" the value "2.0" +will be represented as a REAL number, and the multiplication will be a +REAL multiplication. This will also require that the variable "value" +will have to be transformed into a REAL value, and finally the result of +the expression will have to be transformed back to an INTEGER value if +it is to be assigned to a variable of that type. Thus a single decimal +point will slow this particular operation down by about ten times! +<table frame="none"> +<title>Arithmetic Functions Ranked by Speed</title> +<tgroup cols="2"> +<colspec colwidth="3in"> +<colspec colwidth="2in"> +<thead> +<row> +<entry>Operation</entry> +<entry>Typical Speed (MPU Cycles)</entry> +</row> +</thead> +<tbody> +<row> +<entry>INTEGER ADD OR SUBTRACT</entry> +<entry>150</entry> +</row> +<row> +<entry>INTEGER MULTIPLY</entry> +<entry>240</entry> +</row> +<row> +<entry>REAL ADD</entry> +<entry>440</entry> +</row> +<row> +<entry>REAL SUBTRACT</entry> +<entry>540</entry> +</row> +<row> +<entry>INTEGER DIVIDE</entry> +<entry>960</entry> +</row> +<row> +<entry>REAL MULTIPLY</entry> +<entry>990</entry> +</row> +<row> +<entry>REAL DIVIDE</entry> +<entry>3870</entry> +</row> +<row> +<entry>REAL SQUARE ROOT</entry> +<entry>7360</entry> +</row> +<row> +<entry>REAL LOGARITM OR EXPONENTIAL</entry> +<entry>20400</entry> +</row> +<row> +<entry>REAL SINE OR COSINE</entry> +<entry>32500</entry> +</row> +<row> +<entry>REAL POWER (^)</entry> +<entry>39200</entry> +</row> +</tbody> +</tgroup> +</table> +</para> +<para> +This table can be used to deduce some interesting points. For +example, "value*2" is not optimum - "value+value" can produce the +same result in less time because multiplication takes longer than +addition. Similarly, "value*value" or "SQ(value)" is MUCH faster +than the equivalent "value^2". Another interesting case is "x/2.0". +The REAL divide will cost 3870 cycles, but REAL multiplcation takes +only 990 cycles. The mathematical equivalent to division by a +constant is multiplication by the inverse of the constant. +Therefore, using "X*0.5" instead is almost four times faster! +</para></sect1> + +<sect1><title>Looping Quickly</title> +<para> +When &b09; identifies a FOR..NEXT loop structure with an INTEGER +loop counter variable, it uses a special integer version of the FOR..NEXT +loop. This is much faster than the REAL-type version and is generally +preferable. Other kinds of loops also run faster if INTEGER type variables +are used for loop counters. +</para> +<para> +When writing program loops, remember that statements INSIDE the loop +may be executed many times for each single execution OUTSIDE the loop. +Thus, any value which can be computed before entering a loop will increase +program speed. +</para></sect1> +<sect1><title>Optimum Use of Arrays and Data Structures</title> +<para> +&b09; internally uses INTEGER numbers to index arrays and complex data +structures. If the program uses subscripts that are REAL type variables +or expressions, &b09; has to convert them to INTEGERs before they can +be used. This takes additional time, so use INTEGER expressions for +subscripts whenever you can. +</para> +<para> +Note that the assignment statement (LET) can copy identically sized data +structures. This feature is much faster than copying arrays or structures +element-by-element inside a loop. +</para></sect1> +<sect1><title>The PACK Command</title> +<para> +The PACK command produces a compressed version of a &b09; +procedure. Depending on the number of comments, line numbers, etc., +programs will execute from 10% to 30% faster after being packed. Minimizing +use of line numbers will even speed up procedures that are unPACKed. +</para></sect1> +<sect1><title>Eliminating Constant Expressions and Sub-Expressions</title> +<para> +Consider the expression: +<programlisting> +x = x+SQRT(100)/2 +</programlisting> + +is exactly the same as the expression: +<programlisting> +x = x+5 +</programlisting> +The subexpression "SQRT(100)/2" consists of constants only, so its result +will not vary regardless of the rest of the program. But every time the +program is run, the computer must evaluate it. This time can be significant, +especially if the statement is within a loop. Constant expressions or +subexpressions should be calculated by the programmer while writing the program +(using DEBUG mode or a pocket calculator). +</para></sect1> +<sect1><title>Fast Input and Output Functions</title> +<para> +Reading or writing data a line or record at a time is much faster than a +character at a time. Also, the GET and PUT statements are much faster +than READ and WRITE statements when dealing with disk files. This is +because GET and PUT use the exact binary format used internally by +&b09;. READ, WRITE, PRINT, and INPUT must perform binary-to-ASCII or +ASCII-to-binary conversions which take time. +</para></sect1> +<sect1><title>Professional Programming Techniques</title> +<para> +One sure way to make a program faster is to use the most +efficient algorithms possible. There are many good programming +"cookbooks" that explain useful algorithms with examples in BASIC or PASCAL. +Thanks to &b09;'s rich vocabulary you can use algorithms written in either +language with little or no adaptation. +</para> +<para> +&b09; also eliminates any possible excuse for not using good +structured programming style that produces +efficient, reliable, readable, and maintainable software. &b09; generates +optimized code to be executed by the 6809 which is the most +powerful 8-bit processor in existence at the time of this writing. +But a computer can only execute what +it is told to execute, and no language implementation can make up for an +inefficient program. An inefficient program is evidence of a lack of +understanding of the problem. The result is likely to be hard to understand +and hard to update if program specifications change (they always do). The +identification of efficient algorithms and their clear, structured +expression is indicative of professionalism in software design and is a goal +in itself. +</para> +</sect1> +</chapter> + + + +<appendix> +<title>Sample Programs</title> +<para> +<programlisting> +PROCEDURE fibonacci + REM computes the first ten Fibonacci numbers + DIM x,y,i,temp:INTEGER + + x:=0 \y:=0 + FOR i=0 TO 10 + temp:=y + + IF i<>0 THEN + y:=y+x + ELSE y:=1 + ENDIF + + x:=temp + PRINT i,y + NEXT i +</programlisting> + +<programlisting> +PROCEDURE fractions + REM by T.F. Ritter + REM finds increasinglyclose rational approximations + REM to the desired real value + DIM m:INTEGER + + desired:=PI + last:=0 + + FOR m=1 TO 30000 + n:=INT(.5+m*desired) + trial:=n/m + IF ABS(trialdesired)<ABS(lastdesired) THEN + PRINT n; "/"; m; " = "; trial, + PRINT "difference = "; trialdesired; + PRINT + last:=trial + ENDIF + NEXT m +</programlisting> + +<programlisting> +PROCEDURE prinbi + REM by T.F. Ritter + REM prints the integer parameter value in binary + PARAM n:INTEGER + DIM i:INTEGER + + FOR i=15 TO 0 STEP 1 + IF n<0 THEN + PRINT "1"; + ELSE PRINT "0"; + ENDIF + n:=n+n + NEXT i + PRINT + + END +</programlisting> + +<programlisting> +PROCEDURE hanoi + REM by T.F. Ritter + REM move n discs in Tower of Hanoi game + REM See BYTE Magazine, Oct 1980, pg. 279 + + PARAM n:INTEGER; from,to_,other:STRING[8] + + IF n=1 THEN + PRINT "move #"; n; " from "; from; " to "; to_ + ELSE + RUN hanoi(n1,from,other,to_) + PRINT "move #"; n; " from "; from; " to "; to_ + RUN hanoi(n1,other,to_,from) + ENDIF + + END +</programlisting> + +<programlisting> +PROCEDURE roman + REM prints integer parameter as Roman Numeral + PARAM x:INTEGER + DIM value,svalu,i:INTEGER + DIM char,subs:STRING + + char:="MDCLXVI" + subs:="CCXXII " + DATA 1000,100,500,100,100,10,50,10,10,1,5,1,1,0 + + FOR i=1 TO 7 + READ value + READ svalu + + WHILE x>=value DO + PRINT MID$(char,i,1); + x:=xvalue + ENDWHILE + + IF x>=valuesvalu THEN + PRINT MID$(subs,i,1); MID$(char,i,1); + x:=xvalue+svalu + ENDIF + + NEXT i + END +</programlisting> + +<programlisting> +PROCEDURE eightqueens + REM originally by N. Wirth; here recoded from Pascal + REM finds the arrangements by which eight queens + REM can be placed on a chess board without conflict + DIM n,k,x(8):INTEGER + DIM col(8),up(15),down(15):BOOLEAN + BASE 0 + + (* initialize empty board *) + n:=0 + FOR k:=0 TO 7 \col(k):=TRUE \NEXT k + FOR k:=0 TO 14 \up(k):=TRUE \down(k):=TRUE \NEXT k + RUN generate(n,x,col,up,down) + END + +PROCEDURE generate + PARAM n,x(8):INTEGER + PARAM col(8),up(15),down(15):BOOLEAN + DIM h,k:INTEGER \h:=0 + BASE 0 + + REPEAT + IF col(h) AND up(nh+7) AND down(n+h) THEN + (* set queen on square [n,h] *) + x(n):=h + col(h):=FALSE \up(nh+7):=FALSE \down(n+h) := FALSE + n:=n+1 + IF n=8 THEN + (* board full; print configuration *) + FOR k=0 TO 7 + PRINT x(k); " "; + NEXT k + PRINT + ELSE RUN generate(n,x,col,up,down) + ENDIF + + (* remove queen from square [n,h] *) + n:=n1 + col(h):=TRUE \up(nh+7):=TRUE \down(n+h):=TRUE + ENDIF + h:=h+1 + UNTIL h=8 + END +</programlisting> + +<programlisting> +PROCEDURE electric + REM reprogrammed from "ELECTRIC" + REM by Dwyer and Critchfield + REM Basic and the Personal Computer (AddisonWesley, 1978) + REM provides a pictorial representation of the + REM resultant electrical field around charged points + DIM a(10),b(10),c(10) + DIM x,y,i,j:INTEGER + xscale:=50./78. + yscale:=50./32. + + INPUT "How many charges do you have? ",n + PRINT "The field of view is 050,050 (x,y)" + FOR i=1 TO n + PRINT "type in the x and y positions of charge "; + PRINT i; + INPUT a(i),b(i) + NEXT i + PRINT "type in the size of each charge:" + FOR i=1 TO n + PRINT "charge "; i; + INPUT c(i) + NEXT i + + REM visit each screen position + FOR y=32 TO 0 STEP 1 + FOR x=0 TO 78 + REM compute field strength into v + GOSUB 10 + z:=v*50. + REM map z to valid ASCII in b$ + GOSUB 20 + REM print char (proportional to field) + PRINT b$; + NEXT x + PRINT + NEXT y + END + +10 v=1. + FOR i=1 TO n + r:=SQRT(SQ(xscale*xa(i))+SQ(yscale*yb(i))) + EXITIF r=.0 THEN + v:=99999. + ENDEXIT + v:=v+c(i)/r + NEXT i + RETURN + +20 IF z<32 THEN b$:=" " + ELSE + IF z>57 THEN z:=z+8 + ENDIF + IF z>90 THEN b$:="*" + ELSE + IF z>INT(z)+.5 THEN b$:=" " + ELSE b$:=CHR$(z) + ENDIF + ENDIF + ENDIF + RETURN +</programlisting> + +<programlisting> +PROCEDURE qsort1 + REM quicksort, by T.F. Ritter + PARAM bot,top,d(1000):INTEGER + DIM n,m:INTEGER; btemp:BOOLEAN + + n:=bot + m:=top + + LOOP \REM each element gets the once over + REPEAT \REM this is a postinc instruction + btemp:=d(n)<d(top) + n:=n+1 + UNTIL NOT (btemp) + n:=n1 \REM point at the tested element + EXITIF n=m THEN + ENDEXIT + + REPEAT \REM this is a postdec instruction + m:=m1 + UNTIL d(m)<=d(top) OR m=n + EXITIF n=m THEN + ENDEXIT + + RUN exchange(d(m),d(n)) + n:=n+1 \REM prepare for postinc + EXITIF n=m THEN + ENDEXIT + + ENDLOOP + + IF n<>top THEN + IF d(n)<>d(top) THEN + RUN exchange(d(n),d(top)) + ENDIF + ENDIF + + IF bot<n1 THEN + RUN qsort1(bot,n1,d) + ENDIF + IF n+1<top THEN + RUN qsort1(n+1,top,d) + ENDIF + + END + +PROCEDURE exchange + PARAM a,b:INTEGER + DIM temp:INTEGER + + temp:=a + a:=b + b:=temp + + END + +PROCEDURE prin + PARAM n,m,d(1000):INTEGER + DIM i:INTEGER + + FOR i=n TO m + PRINT d(i); + NEXT i + PRINT + + END + +PROCEDURE sortest + REM This procedure is used to test Quicksort + REM It fills the array "d" with randomly generated + REM numbers and sorts them. + DIM i,d(1000):INTEGER + + FOR i=1 TO 1000 + d(i):=INT(RND(100)) + NEXT i + + RUN prin(1,1000,d) + + RUN qsort1(1,1000,d) + + RUN prin(1,1000,d) + + END +</programlisting> + +<programlisting> +PROCEDURE structst + + REM example of intermixed array and record structures + REM note that structure d contains 200 real elements + + TYPE a=one(2):REAL + TYPE b=two(10):a + TYPE c=three(10):b + DIM d,e:c + + FOR i=1 TO 10 + FOR j=1 TO 10 + FOR k=1 TO 2 + PRINT d.three(i).two(j).one(k) + d.three(i).two(j).one(k):=0. + PRINT e.three(i).two(j).one(k) + PRINT + NEXT k + NEXT j + NEXT i + + REM this is a complete structure assignment + e:=d + + FOR i=1 TO 10 + FOR j=1 TO 10 + FOR k=1 TO 2 + PRINT e.three(i).two(j).one(k); + NEXT k + PRINT + NEXT j + NEXT i + + END +</programlisting> + +<programlisting> +PROCEDURE pialook + REM display PIA at address (T.F. Ritte) + REM made understandable by K. Kaplan + + DIM address:INTEGER + INPUT "Enter PIA address: "; address + RUN side(address) + RUN side(adress+2) + END + +PROCEDURE side + REM display side of PIA at address + PARAM address:INTEGER + DIM data:INTEGER + + (* loop until control register input strobe + (* flag (bit 7) is set + REPEAT \ UNTIL LAND(PEEK(address+1),$80) <> 0 + (* now read the data register + data := PEEK(address) + (* display data in binary + RUN prinbyte(data) + END + +PROCEDURE prinbyte + REM print a byte as binary + PARAM n: INTEGER + DIM i: INTEGER + + n:= n*256 + FOR i = 7 TO 0 STEP 1 + IF n < 0 THEN PRINT "1"; + ELSE PRINT "0"; + ENDIF + n:= n + 1 + NEXT i + + PRINT + END +</programlisting> + +</para> +<para> +The following procedures demonstrate multiple-precision arithmetic, in +this case using five integers to represent a twenty decimal digit number, with +four fractional places. +</para> +<para> + + +<programlisting> +PROCEDURE mpadd + REM a+b=>c:five_integer_number (T.F. Ritter) + PARAM a(5),b(5),c(5):INTEGER + DIM i,carry:INTEGER + + carry:=0 + FOR i=5 TO 1 STEP 1 + c(i):=a(i)+b(i)+carry + IF c(i)>=10000 THEN + c(i):=c(i)10000 + carry:=1 + ELSE carry:=0 + ENDIF + NEXT i +</programlisting> + +<programlisting> + +PROCEDURE mpsub + PARAM a(5),b(5),c(5):INTEGER + DIM i,borrow:INTEGER + + borrow:=0 + FOR i=5 TO 1 STEP 1 + c(i):=a(i)b(i)borrow + IF c(i)<0 THEN + c(i):=c(i)+10000 + borrow:=1 + ELSE borrow:=0 + ENDIF + NEXT i +</programlisting> + +<programlisting> + +PROCEDURE mprint + PARAM a(5):INTEGER + DIM i:INTEGER; s:STRING + + FOR i=1 TO 5 + IF i=5 THEN PRINT "."; + ENDIF + s:=STR$(a(i)) + PRINT MID$("0000"+s,LEN(s)+1,4); + NEXT i +</programlisting> + +<programlisting> +PROCEDURE mpinput + PARAM a(5):INTEGER + DIM n,i:INTEGER + + INPUT "input ultraprecision number: ",b$ + n:=SUBSTR(".",b$) + + IF n<>0 THEN + a(5):=VAL(MID$(b$+"0000",n+1,4)) + b$:=LEFT$(b$,n1) + ELSE a(5):=0 + ENDIF + + b$:="00000000000000000000"+b$ + n:=1+LEN(b$) + FOR i=4 TO 1 STEP 1 + n:=n4 + a(i):=VAL(MID$(b$,n,4)) + NEXT i +</programlisting> + +<programlisting> + +PROCEDURE mptoreal + PARAM a(5):INTEGER; b:REAL + DIM i:INTEGER + + b:=a(1) + FOR i=2 TO 4 + b:=b*10000 + b:=b+a(i) + NEXT i + b:=b+a(5)*.0001 +</programlisting> + +<programlisting> +PROCEDURE Patch + (* Program to examine and patch any byte of a disk file *) + (* Written by L. Crane *) + DIM buffer(256):BYTE + DIM path,offset,modloc:INTEGER; loc:REAL + DIM rewrite:STRING + INPUT "pathlist? ",rewrite + OPEN #path,rewrite:UPDATE + LOOP + INPUT "sector number? ",rewrite + EXITIF rewrite="" THEN ENDEXIT + loc=VAL(rewrite)*256 + SEEK #path,loc + GET #path,buffer + RUN DumpBuffer(loc,buffer) + LOOP + INPUT "change (sector offset)? ",rewrite + EXITIF rewrite="" THEN + RUN DumpBuffer(loc,buffer) + ENDEXIT + EXITIF rewrite="S" OR rewrite="s" THEN ENDEXIT + offset=VAL(rewrite)+1 + LOOP + EXITIF offset>256 THEN ENDEXIT + modloc=loc+offset1 + PRINT USING "h4,' ',h2",modloc,buffer(offset); + INPUT ":",rewrite + EXITIF rewrite="" THEN ENDEXIT + IF rewrite<>" " THEN + buffer(offset)=VAL(rewrite) + ENDIF + offset=offset+1 + ENDLOOP + ENDLOOP + INPUT "rewrite sector? ",rewrite + IF LEFT$(rewrite,1)="Y" OR LEFT$(rewrite,1)="y" THEN + SEEK #path,loc + PUT #path,buffer + ENDIF + ENDLOOP + CLOSE #path + BYE + +PROCEDURE DumpBuffer + (* Called by PATCH *) + TYPE buffer=char(8):INTEGER + PARAM loc:REAL; line(16):buffer + DIM i,j:INTEGER + WHILE loc>65535. DO + loc=loc65536. + ENDWHILE + FOR j=1 TO 16 + PRINT USING "h4",FIX(INT(loc))+(j1)*16; + PRINT ":"; + FOR i=1 TO 8 + PRINT USING "X1,H4",line(j).char(i); + NEXT i + RUN printascii(line(j)) + PRINT + NEXT j + +PROCEDURE PrintASCII + TYPE buffer=char(16):BYTE + PARAM line:buffer + DIM ascii:STRING; nextchar:BYTE; i:INTEGER + ascii="" + FOR i=1 TO 16 + nextchar=line.char(i) + IF nextchar>127 THEN + nextchar=nextchar128 + ENDIF + IF nextchar<32 OR nextchar>125 THEN + ascii=ascii+" " + ELSE + ascii=ascii+CHR$(nextchar) + ENDIF + NEXT i + PRINT " "; ascii; +</programlisting> + +<programlisting> + PROCEDURE MakeProc + (* Generates an OS9 command file to apply a command *) + (* Such as copy, del, etc., to all files in a directory *) + (* or directory system. Author: L. Crane *) + + DIM DirPath,ProcPath,i,j,k:INTEGER + DIM CopyAll,CopyFile:BOOLEAN + DIM ProcName,FileName,ReInput,ReOutput,response:STRING + DIM SrcDir,DestDir,DirLine:STRING[80] + DIM Function,Options:STRING[60] + DIM ProcLine:STRING[160] + + ProcName="CopyDir" + Function="Copy" + Options="#32k" + REPEAT + PRINT "Proc name ("; ProcName; ")"; + INPUT response + IF response<>"" THEN + ProcName=TRIM$(response) + ENDIF + + ON ERROR GOTO 100 + SHELL "del "+ProcName +100 ON ERROR + INPUT "Source Directory? ",SrcDir + SrcDir=TRIM$(SrcDir) + ON ERROR GOTO 200 + SHELL "del procmaker...dir" +200 ON ERROR + SHELL "dir "+SrcDir+" >procmaker...dir" + OPEN #DirPath,"procmaker...dir":READ + CREATE #ProcPath,ProcName:WRITE + PRINT "Function ("; Function; ")"; + INPUT response + IF response<>"" THEN + Function=TRIM$(response) + ENDIF + INPUT "Redirect Input? ",response + IF response="y" OR response="Y" THEN + ReInput="<" \ ELSE \ReInput="" + ENDIF + INPUT "Redirect Output? ",response + IF response="y" OR response="Y" THEN + ReOutput=">" \ ELSE \ReOutput="" + ENDIF + PRINT "Options ("; Options; ")"; + INPUT response + IF response<>"" THEN + Options=TRIM$(response) + ENDIF + INPUT "Destination Directory? ",DestDir + DestDir=TRIM$(DestDir) + WRITE #ProcPath,"t" + WRITE #ProcPath,"TMode .1 pause" + READ #DirPath,DirLine + INPUT "Use all files? ",response + CopyAll=response="y" OR response="Y" + WHILE NOT(EOF(#DirPath)) DO + READ #DirPath,DirLine + i=LEN(TRIM$(DirLine)) + IF i>0 THEN + j=1 + REPEAT + k=j + WHILE j<=i AND MID$(DirLine,j,1)<>" " DO + j=j+1 + ENDWHILE + FileName=MID$(DirLine,k,jk) + IF NOT(CopyAll) THEN + PRINT "Use "; FileName; + INPUT response + CopyFile=response="y" OR response="Y" + ENDIF + IF CopyAll OR CopyFile THEN + ProcLine=Function+" "+ReInput+SrcDir+"/"+FileName + IF DestDir<>"" THEN + ProcLine=ProcLine+" "+ReOutput+DestDir+"/"+FileName + ENDIF + ProcLine=ProcLine+" "+Options + WRITE #ProcPath,ProcLine + ENDIF + WHILE j<i AND MID$(DirLine,j,1)=" " DO + j=j+1 + ENDWHILE + UNTIL j>=i + ENDIF + ENDWHILE + WRITE #ProcPath,"TMode .1 pause" + WRITE #ProcPath,"Dir e "+SrcDir + IF DestDir<>"" THEN + WRITE #ProcPath,"Dir e "+DestDir + ENDIF + CLOSE #DirPath + CLOSE #ProcPath + SHELL "del procmaker...dir" + PRINT + INPUT "Another ? ",response + UNTIL response<>"Y" AND response<>"y" + IF response<>"B" AND response<>"b" THEN + BYE + ENDIF +</programlisting> + +<programlisting> +*************** +* INKEY - a subroutine for BASIC09 by Robert Doggett + +* Called by: RUN INKEY(StrVar) +* RUN INKEY(Path, StrVar) +* Inkey determines if a key has been typed on the given path +* (Standard Input if not specified), and if so, returns the next +* character in the String Variable. If no key has been type, the +* null string is returned. If a path is specified, it must be +* either type BYTE or INTEGER. + + 0021 TYPE set SBRTN+OBJCT + 0081 REVS set REENT+1 + + 0000 87CD005E mod InKeyEnd,InKeyNam,TYPE,REVS + ,InKeyEnt,0 + 000D 496E6B65 InKeyNam fcs "Inkey" +D 0000 org 0 Parameters +D 0000 Return rmb 2 Return addr of caller +D 0002 PCount rmb 2 Num of params following +D 0004 Param1 rmb 2 1st param addr +D 0006 Length1 rmb 2 size +D 0008 Param2 rmb 2 2nd param addr +D 000A Length2 rmb 2 size + 0012 3064 InKeyEnt leax Param1,S + 0014 EC62 ldd PCount,S Get parameter count + 0016 10830001 cmpd #1 just one parameter? + 001A 2717 beq InKey20 ..Yes; default path A=0 + 001C 10830002 cmpd #2 Are there two params? + 0020 2635 bne ParamErr No, abort + 0022 ECF804 ldd [Param1,S] Get path number + 0025 AE66 ldx Length1,S + 0027 301F leax -1,X byte available? + 0029 2706 beq InKey10 ..Yes; (A)=Path number + 002B 301F leax -1,X Integer? + 002D 2628 bne ParamErr ..No; abort + 002F 1F98 tfr B,A + 0031 3068 InKey10 leax Param2,S + 0033 EE02 InKey20 ldu 2,X length of string + 0035 AE84 ldx 0,X addr of string + 0037 C6FF ldb #$FF + 0039 E784 stb 0,X Initialize to null str + 003B 11830002 cmpu #2 at least two-byte str? + 003F 2502 blo InKey30 ..No + 0041 E701 stb 1,X put str terminator + 0043 C601 InKey30 ldb #SS.Ready + 0045 103F8D OS9 I$GetStt is there an data ready? + 0048 2508 bcs InKey90 ..No; exit + 004A 108E0001 ldy #1 + 004E 103F89 OS9 I$Read Read one byte + 0051 39 rts + 0052 C1F6 InKey90 cmpb #E$NotRdy + 0054 2603 bne InKeyErr + 0056 39 rts (carry clear) + 0057 C638 ParamErr ldb #E$Param Parameter Error + 0059 43 InKeyErr coma + 005A 39 rts + 005B 1A6926 emod + 005E InKeyEnd equ * +</programlisting> + +</para> +</appendix> +<appendix> +<title>Quick Reference</title> +<para> + + +<table frame="none"> +<title>System Mode Commands</title> +<tgroup cols="5"> +<tbody> +<row> +<entry>$</entry> +<entry>CHX</entry> +<entry>EDIT</entry> +<entry>LOAD</entry> +<entry>RENAME</entry> +</row> +<row> +<entry>BYE</entry> +<entry>DIR</entry> +<entry>KILL</entry> +<entry>MEM</entry> +<entry>RUN</entry> +</row> +<row> +<entry>CHD</entry> +<entry>E</entry> +<entry>LIST</entry> +<entry>PACK</entry> +<entry>SAVE</entry> +</row> +</tbody> +</tgroup> +</table> + + +<table frame="none"> +<title>Edit Mode Commands</title> +<tgroup cols="5"> +<tbody> +<row> +<entry>+</entry> +<entry><cr></entry> +<entry>c*</entry> +<entry>l*</entry> +<entry>r*</entry> +</row> +<row> +<entry>+*</entry> +<entry><line #></entry> +<entry>d</entry> +<entry>q</entry> +<entry>s</entry> +</row> +<row> +<entry>-</entry> +<entry><space></entry> +<entry>d*</entry> +<entry>r</entry> +<entry>s*</entry> +</row> +<row> +<entry>-*</entry> +<entry>c</entry> +<entry>l</entry> +<entry></entry> +<entry></entry> +</row> +</tbody> +</tgroup> +</table> + + +<table frame="none"> +<title>Debug Mode Commands</title> +<tgroup cols="5"> +<tbody> +<row> +<entry>$</entry> +<entry>DEG</entry> +<entry>LET</entry> +<entry>Q</entry> +<entry>STEP</entry> +</row> +<row> +<entry>BREAK</entry> +<entry>DIR</entry> +<entry>LIST</entry> +<entry>RAD</entry> +<entry>TROFF</entry> +</row> +<row> +<entry>CONT</entry> +<entry>END</entry> +<entry>PRINT</entry> +<entry>STATE</entry> +<entry>TRON</entry> +</row> +</tbody> +</tgroup> +</table> + + + +<table frame="none"> +<title>Program Reserved Words</title> +<tgroup cols=5> +<tbody> +<row> +<entry>ABS</entry> +<entry>DIR</entry> +<entry>INT</entry> +<entry>PEEK</entry> +<entry>SQR</entry> +</row> +<row> +<entry>ACS</entry> +<entry>DO</entry> +<entry>INTEGER</entry> +<entry>PI</entry> +<entry>SQRT</entry> +</row> +<row> +<entry>ADDR</entry> +<entry>ELSE</entry> +<entry>KILL</entry> +<entry>POKE</entry> +<entry>STEP</entry> +</row> +<row> +<entry>AND</entry> +<entry>END</entry> +<entry>LAND</entry> +<entry>POS</entry> +<entry>STOP</entry> +</row> +<row> +<entry>ASC</entry> +<entry>ENDEXIT</entry> +<entry>LEFT$</entry> +<entry>PRINT</entry> +<entry>STR$</entry> +</row> +<row> +<entry>ASN</entry> +<entry>ENDIF</entry> +<entry>LEN</entry> +<entry>PROCEDURE</entry> +<entry>STRING</entry> +</row> +<row> +<entry>ATN</entry> +<entry>ENDLOOP</entry> +<entry>LET</entry> +<entry>PUT</entry> +<entry>SUBSTR</entry> +</row> +<row> +<entry>BASE</entry> +<entry>ENDWHILE</entry> +<entry>LNOT</entry> +<entry>RAD</entry> +<entry>TAB</entry> +</row> +<row> +<entry>BOOLEAN</entry> +<entry>EOF</entry> +<entry>LOG</entry> +<entry>READ</entry> +<entry>TAN</entry> +</row> +<row> +<entry>BYE</entry> +<entry>ERR</entry> +<entry>LOG10</entry> +<entry>REAL</entry> +<entry>THEN</entry> +</row> +<row> +<entry>BYTE</entry> +<entry>ERROR</entry> +<entry>LOOP</entry> +<entry>REM</entry> +<entry>TO</entry> +</row> +<row> +<entry>CHAIN</entry> +<entry>EXEC</entry> +<entry>LOR</entry> +<entry>REPEAT</entry> +<entry>TRIM$</entry> +</row> +<row> +<entry>CHD</entry> +<entry>EXITIF</entry> +<entry>LXOR</entry> +<entry>RESTORE</entry> +<entry>TROFF</entry> +</row> +<row> +<entry>CHR$</entry> +<entry>EXP</entry> +<entry>MID$</entry> +<entry>RETURN</entry> +<entry>TRON</entry> +</row> +<row> +<entry>CHX</entry> +<entry>FALSE</entry> +<entry>MOD</entry> +<entry>RIGHT$</entry> +<entry>TRUE</entry> +</row> +<row> +<entry>CLOSE</entry> +<entry>FIX</entry> +<entry>NEXT</entry> +<entry>RND</entry> +<entry>TYPE</entry> +</row> +<row> +<entry>COS</entry> +<entry>FLOAT</entry> +<entry>NOT</entry> +<entry>RUN</entry> +<entry>UNTIL</entry> +</row> +<row> +<entry>CREATE</entry> +<entry>FOR</entry> +<entry>ON</entry> +<entry>SEEK</entry> +<entry>UPDATE</entry> +</row> +<row> +<entry>DATA</entry> +<entry>GET</entry> +<entry>OPEN</entry> +<entry>SGN</entry> +<entry>USING</entry> +</row> +<row> +<entry>DATE$</entry> +<entry>GOSUB</entry> +<entry>OR</entry> +<entry>SHELL</entry> +<entry>VAL</entry> +</row> +<row> +<entry>DEG</entry> +<entry>GOTO</entry> +<entry>PARAM</entry> +<entry>SIN</entry> +<entry>WHILE</entry> +</row> +<row> +<entry>DELETE</entry> +<entry>IF</entry> +<entry>PAUSE</entry> +<entry>SIZE</entry> +<entry>WRITE</entry> +</row> +<row> +<entry>DIM</entry> +<entry>INPUT</entry> +<entry></entry> +<entry>SQ</entry> +<entry>XOR</entry> +</row> +</tbody> +</tgroup> +</table> + + +<table frame="none"> +<title>&b09; Statements</title> +<tgroup cols="5"> +<tbody> +<row> +<entry>BASE 0</entry> +<entry>ELSE</entry> +<entry>GOTO</entry> +<entry>OPEN</entry> +<entry>RETURN</entry> +</row> +<row> +<entry>BASE 1</entry> +<entry>END</entry> +<entry>IF/THEN</entry> +<entry>PARAM</entry> +<entry>RUN</entry> +</row> +<row> +<entry>BYE</entry> +<entry>ENDEXIT</entry> +<entry>INPUT</entry> +<entry>PAUSE</entry> +<entry>SEEK</entry> +</row> +<row> +<entry>CHAIN</entry> +<entry>ENDIF</entry> +<entry>KILL</entry> +<entry>POKE</entry> +<entry>SHELL</entry> +</row> +<row> +<entry>CHD</entry> +<entry>ENDLOOP</entry> +<entry>LET</entry> +<entry>PRINT</entry> +<entry>STOP</entry> +</row> +<row> +<entry>CHX</entry> +<entry>ENDWHILE</entry> +<entry>LOOP</entry> +<entry>PUT</entry> +<entry>TROFF</entry> +</row> +<row> +<entry>CLOSE</entry> +<entry>ERROR</entry> +<entry>NEXT</entry> +<entry>RAD</entry> +<entry>TRON</entry> +</row> +<row> +<entry>CREATE</entry> +<entry>EXITIF/THEN</entry> +<entry>ON ERROR GOTO</entry> +<entry>READ</entry> +<entry>TYPE</entry> +</row> +<row> +<entry>DATA</entry> +<entry>FOR/TO/STEP</entry> +<entry>ON/GOSUB</entry> +<entry>REM</entry> +<entry>UNTIL</entry> +</row> +<row> +<entry>DEG</entry> +<entry>GET</entry> +<entry>ON/GOTO</entry> +<entry>REPEAT</entry> +<entry>WHILE/DO</entry> +</row> +<row> +<entry>DELETE</entry> +<entry>GOSUB</entry> +<entry></entry> +<entry>RESTORE</entry> +<entry>WRITE</entry> +</row> +<row> +<entry>DIM</entry> +<entry></entry> +<entry></entry> +<entry></entry> +<entry></entry> +</row> +</tbody> +</tgroup> +</table> + + +<table frame="none"> +<title>Transcendental Functions</title> +<tgroup cols="4"> +<tbody> +<row> +<entry>ACS (x)</entry> +<entry>COS (x)</entry> +<entry>LOG10 (x)</entry> +<entry>SIN (x)</entry> +</row> +<row> +<entry>ASN (x)</entry> +<entry>EXP (x)</entry> +<entry>PI</entry> +<entry>TAN (x)</entry> +</row> +<row> +<entry>ATN (x)</entry> +<entry>LOG (x)</entry> +</row> +</tbody> +</tgroup> +</table> + + +<table frame="none"> +<title>Numeric Functions</title> +<tgroup cols="4"> +<tbody> +<row> +<entry>ABS (x)</entry> +<entry>LAND (m,n)</entry> +<entry>MOD (m,n)</entry> +<entry>SQ (x)</entry> +</row> +<row> +<entry>FIX (x)</entry> +<entry>LNOT (m,n)</entry> +<entry>RND (x)</entry> +<entry>SQR (x)</entry> +</row> +<row> +<entry>FLOAT (m)</entry> +<entry>LOR (m,n)</entry> +<entry>SGN (x)</entry> +<entry>SQRT (x)</entry> +</row> +<row> +<entry>INT (x)</entry> +<entry>LXOR (m,n)</entry> +</row> +</tbody> +</tgroup> +</table> + +<table frame="none"> +<title>String Functions</title> +<tgroup cols="4"> +<tbody> +<row> +<entry>ASC (char$)</entry> +<entry>LEFT$ (str$,m)</entry> +<entry>RIGHT$ (str$,m)</entry> +<entry>TRIM$ (str$)</entry> +</row> +<row> +<entry>CHR$ (m)</entry> +<entry>LEN (str$)</entry> +<entry>STR$ (x)</entry> +<entry>VAL(str$)</entry> +</row> +<row> +<entry>DATE$</entry> +<entry>MID$ (str$,m,n)</entry> +<entry>SUBSTR(st1$,st2$)</entry> +</row> +</tbody> +</tgroup> +</table> + +<table frame="none"> +<title>Miscellaneous Functions</title> +<tgroup cols="4"> +<tbody> +<row> +<entry>ADDR (var)</entry> +<entry>FALSE</entry> +<entry>POS</entry> +<entry>TAB (m)</entry> +</row> +<row> +<entry>EOF (#path)</entry> +<entry>PEEK (addr)</entry> +<entry>SIZE (var)</entry> +<entry>TRUE</entry> +</row> +<row> +<entry>ERR</entry> +</row> +</tbody> +</tgroup> +</table> + +<table frame="none"> +<title>Operator Precedence</title> +<tgroup cols="7"> +<colspec colname="c1"> +<colspec colname="c2"> +<colspec colname="c3"> +<colspec colnum=7 colname="c7"> +<spanspec spanname="firstop" namest="c2" nameend="c2"> +<spanspec spanname="secondop" namest="c3" nameend="c7"> +<spanspec spanname="onlyop" namest="c2" nameend="c7"> +<spanspec spanname="all" namest="c1" nameend="c7"> +<tbody> +<row> +<entry>highest -></entry> +<entry spanname="firstop">NOT</entry> +<entry spanname="secondop">(negate)</entry> +</row> +<row> +<entry spanname="firstop">^</entry> +<entry spanname="secondop">**</entry> +</row> +<row> +<entry spanname="firstop">*</entry> +<entry spanname="secondop">/</entry> +</row> +<row> +<entry spanname="firstop">+</entry> +<entry spanname="secondop"></entry> +</row> +<row> +<entry spanname="firstop">></entry> +<entry><</entry> +<entry><></entry> +<entry>=</entry> +<entry>>=</entry> +<entry><=</entry> +</row> +<row> +<entry spanname="onlyop">AND</entry> +</row> +<row> +<entry>lowest -></entry> +<entry spanname="firstop">OR</entry> +<entry spanname="secondop">XOR</entry> +</row> +</tbody> +</tgroup> +</table> + + +</para> +</appendix> +<appendix> +<title>&b09; Error Codes</title> +<para> +<literallayout> +10 Unrecognized Symbol +11 Excessive Verbage (too many keywords or symbols) +12 Illegal Statement Construction +13 I-code Overflow (need more workspace memory) +14 Illegal Channel Reference (bad path number given) +15 Illegal Mode (Read/Write/Update/Dir only) +16 Illegal Number +17 Illegal Prefix +18 Illegal Operand +19 Illegal Operator + +20 Illegal Record Field Name +21 Illegal Dimension +22 Illegal Literal +23 Illegal Relational +24 Illegal Type Suffix +25 Too-Large Dimension +26 Too-Large Line Number +27 Missing Assignment Statement +28 Missing Path Number +29 Missing Comma + +30 Missing Dimension +31 Missing DO Statement +32 Memory Full (need more workspace memory) +33 Missing GOTO +34 Missing Left Parenthesis +35 Missing Line Reference +36 Missing Operand +37 Missing Right Parenthesis +38 Missing THEN statement +39 Missing TO + +40 Missing Variable Reference +41 No Ending Quote +42 Too Many Subscripts +43 Unknown Procedure +44 Multiply-Defined Procedure +45 Divide by Zero +46 Operand Type Mismatch +47 String Stack Overflow +48 Unimplemented Routine +49 Undefined Variable + +50 Floating Overflow +51 Line with Compiler Error +52 Value out of Range for Destination +53 Subroutine Stack Overflow +54 Subroutine Stack Underflow +55 Subscript out of Range +56 Parameter Error +57 System Stack Overflow +58 I/O Type Mismatch +59 I/O Numeric Input Format Bad + +60 I/O Conversion: Number out of Range +61 Illegal Input Format +62 I/O Format Repeat Error +63 I/O Format Syntax Error +64 Illegal Path Number +65 Wrong Number of Subscripts +66 Non-Record-Type Operand +67 Illegal Argument +68 Illegal Control Structure +69 Unmatched Control Structure + +70 Illegal FOR Variable +71 Illegal Expression Type +72 Illegal Declarative Statement +73 Array Size Overflow +74 Undefined Line Number +75 Multiply-Defined Line Number +76 Multiply-Defined Variable +77 Illegal Input Variable +78 Seek Out of Range +79 Missing Data Statement +80 Print Buffer Overflow +</literallayout> + +Error codes above 80 are those used by OS-9 or other external programs. +Consult the "OS-9 User's Guide" for a list of error codes and explanations. +</para> +</appendix> + + +<appendix> +<title>The &b09; Graphics Interface Module</title> +<para> +The Graphics Interface module provides a simple and convenient +way to access the colour graphics and joystick functions of the +Dragon Computer from &b09; programs. The module is a program +written in assembly language and stored in a file called "GFX". It +can be loaded into memory using the OS-9 "LOAD" command prior to or +after called &b09;, or it will be automatically called by &b09; +the first time it is referenced in a program if the "GFX" file is +located in the execution ("CMDS") directory. +</para> +<para> +"GFX" is called using the &b09; "RUN" statement. The first +parameter passed is the name of the graphics function desired. +Other parameters are used to pass coordinates, colour modes, etc. +</para> +<para> +The are two basic graphics modes: 4-colour having 128 by 192 +pixel resolution, and 2-colour having 256 by 192 pixel resolution. +The display is treated as a 256 by 192 point grid with coordinates +0,0 in the lower left-hand corner. X (horizontal) coordinates in +either mode must be in the range of 0 to 255. An X-coordinate +greater than 255 will cause a run-time error. Y coordinates +(vertical) must be in the range of 0 to 191. A number greater than +191 will be replaced by 191. Some of the graphics functions require +or optionally accept a colour mode which controls the foreground +colour and colour set. The mode and colour codes are given in the +table on the next page. +</para> +<beginpage> +<table frame="none"> + <title>Colour Graphics Modes and Colour Codes</title> +<tgroup cols="6"> +<colspec colname="c1"> +<colspec colname="c2"> +<colspec colname="c3"> +<colspec colname="c4"> +<colspec colname="c5"> +<colspec colname="c6"> +<thead> +<row> +<entry morerows=1 namest="c2">Colour Code</entry> +<entry align="center" nameend="c4">Two Colour Format</entry> +<entry align="center" nameend="c6">Four Colour Format</entry> +</row> +<row> +<entry namest="c3">Background</entry> +<entry namest="c4">Foreground</entry> +<entry namest="c5">Background</entry> +<entry namest="c6">Foreground</entry> +</row> +</thead> +<tbody> +<row> +<entry morerows=3 valign=middle>Colour Set 1</entry> +<entry align="center">00</entry> +<entry align="left">Black</entry> +<entry align="left">Black</entry> +<entry align="left">Green</entry> +<entry align="left">Green</entry> +</row> +<row> +<entry align="center">01</entry> +<entry align="left">Black</entry> +<entry align="left">Green</entry> +<entry align="left">Green</entry> +<entry align="left">Yellow</entry> +</row> +<row> +<entry align="center">02</entry> +<entry namest="c5" align="left">Green</entry> +<entry align="left">Blue</entry> +</row> +<row rowsep=1> +<entry align="center">03</entry> +<entry namest="c5" align="left">Green</entry> +<entry align="left">Red</entry> +</row> +<row> +<entry morerows=3 valign=middle>Colour Set 2</entry> +<entry align="center">04</entry> +<entry align="left">Black</entry> +<entry align="left">Black</entry> +<entry align="left">Buff</entry> +<entry align="left">Buff</entry> +</row> +<row> +<entry align="center" namest="c2">05</entry> +<entry align="left">Black</entry> +<entry align="left">Buff</entry> +<entry align="left">Buff</entry> +<entry align="left">Cyan</entry> +</row> +<row> +<entry align="center" namest="c2">06</entry> +<entry namest="c5" align="left">Buff</entry> +<entry align="left">Magenta</entry> +</row> +<row rowsep=1> +<entry align="center" namest="c2">07</entry> +<entry namest="c5" align="left">Buff</entry> +<entry align="left">Orange</entry> +</row> +<row> +<entry morerows=3 valign=middle>Colour Set 3*</entry> +<entry align="center">08</entry> +<entry namest="c5" align="left">Black</entry> +<entry align="left">Black</entry> +</row> +<row> +<entry align="center" namest="c2">09</entry> +<entry namest="c5" align="left">Black</entry> +<entry align="left">Dark Green</entry> +</row> +<row> +<entry align="center" namest="c2">10</entry> +<entry namest="c5" align="left">Black</entry> +<entry align="left">Med. Green</entry> +</row> +<row rowsep=1> +<entry align="center" namest="c2">11</entry> +<entry namest="c5" align="left">Black</entry> +<entry align="left">Light Green</entry> +</row> +<row> +<entry morerows=3 valign=middle>Colour Set 4*</entry> +<entry align="center">12</entry> +<entry namest="c5" align="left">Black</entry> +<entry align="left">Black</entry> +</row> +<row> +<entry align="center" namest="c2">13</entry> +<entry namest="c5" align="left">Black</entry> +<entry align="left">Green</entry> +</row> +<row> +<entry align="center" namest="c2">14</entry> +<entry namest="c5" align="left">Black</entry> +<entry align="left">Red</entry> +</row> +<row> +<entry align="center" namest="c2">15</entry> +<entry namest="c5" align="left">Black</entry> +<entry align="left">Buff</entry> +</row> +</tbody> +</tgroup> +</table> +<note> +<para> +Colour Sets 3 and 4 are not available on PAL video system +(U.K. and European) models. +</para> +</note> +<bridgehead renderas="sect2">MODE</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Mode",Format,Colour)</command> +</cmdsynopsis> +<para> +MODE switches the screen from alphanumeric to graphics display mode, +and selects the screen mode and colour mode. "Format" determines +between two-colour (Format = 0), or four-colour (Format = 1) +graphics modes. "Colour" is the initial colour code that specifies +the foreground colour and colour set. +</para> +<para> +This command must be given before aby other graphics command is +used. The first time MODE is called, it requests 6K bytres of memory +from OS-9 for use as the graphics display memory. MODE will return +an error if sufficient free memory is not available. +</para> +<para> +An example: +<programlisting> +RUN GFX("Mode",1,3) +</programlisting> +selects four-colour mode graphics is used, and the initial +foreground colour is red. +</para> +<bridgehead renderas="sect2">MOVE</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Move",X,Y)</command> +</cmdsynopsis> +<para> +MOVE positions the (invisible) graphics cursor to the specified +location without changing the display. X and Y are the coordinates +of the new position. +</para> +<para> +Example: +<programlisting> +RUN GFX("Move",0,0) +</programlisting> +This example positions the cursor in the lower left-hand corner. +</para> +<bridgehead renderas="sect2">COLOR</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Color",Colour)</command> +</cmdsynopsis> +<para> +COLOR changes the current foreground colour (and possibly the colour +set). The current graphics mode and cursor position are not +changed. For example: +<programlisting> +RUN GFX("Color",0) +</programlisting> +changes the foreground colour to green in four-colour format (or +black in two-colour format). +</para> +<bridgehead renderas="sect2">POINT</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Point",X,Y) or</command><sbr> +<command>RUN GFX("Point",X,Y,Colour)</command> +</cmdsynopsis> +<para> +POINT moves the graphics cursor to the specified X.Y coordinate and +sets the pixel at that coordinate to the current foreground colour. +If the optional "Colour" is specified, the current foreground colour +is set to the given "Colour". For example: +<programlisting> +RUN GFX("Point",0,192,1) +</programlisting> +Point moves the cursor to the upper left-hand corner and changes +the foreground colour to green in two-colour format, or it changes +the colour to yellow in the four-colour format. +</para> +<bridgehead renderas="sect2">CLEAR</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Clear") or</command><sbr> +<command>RUN GFX("Clear",Colour)</command> +</cmdsynopsis> +<para> +CLEAR resets all points on the screen to the background colour, or +if the optional colour is given presets the screen to that colour. +The current graphics cursor is reset to (0,0). +</para> +<bridgehead renderas="sect2">LINE</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Line",x2,y2)</command><sbr> +<command>RUN GFX("Line",x2,y2,Colour)</command><sbr> +<command>RUN GFX("Line",x1,y1,x2,y2)</command><sbr> +<command>RUN GFX("Line",x1,y1,x2,y2,Colour)</command> +</cmdsynopsis> +<para> +LINE draw lines in various ways. If one coordinate is given, the +line will be drawn from the current graphics cursor position to the +coordinates specified. If two sets of coordinates are given, they +are used as the start and end points of the line. The line will be +drawn in the current foreground colour unless a new colour is given +as a parameter. After the line is drawn the graphics cursor will be +positioned at x2,y2. For example +<programlisting> +RUN GFX("Line",0,0,0,192) +</programlisting> +draws a line from (0,0) to (0,192). +<programlisting> +RUN GFX("line",24,65,2) +</programlisting> +draws a blue line (4-colour mode) to point 24,65. +</para> +<bridgehead renderas="sect2">CIRCLE</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Circle",Radius)</command><sbr> +<command>RUN GFX("Circle",Radius,Colour)</command><sbr> +<command>RUN GFX("Circle",X,Y,Radius)</command><sbr> +<command>RUN GFX("Circle",X,Y,Radius,Colour)</command> +</cmdsynopsis> +<para> +CIRCLE draws a circle of the given radius. The current graphics +cursor position is assumed if no X,Y value is given. The current +foreground colour is assumed if the Colour parameter is not used. +The center of the circle must be on the screen. +</para> +<bridgehead renderas="sect2">ALPHA</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Alpha")</command> +</cmdsynopsis> +<para> +Alpha is a quick convenient way of getting the screen back to +alphanumeric mode. When graphics mode is entered again, the screen +will show the previous unchanged graphics display. +</para> +<bridgehead renderas="sect2">QUIT</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Quit")</command> +</cmdsynopsis> +<para> +QUIT switches the screen back to alpha mode and returns the 6K byte +graphics display memory to OS-9. +</para> +<bridgehead renderas="sect2">GLOC</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Gloc",Vdisp)</command> +</cmdsynopsis> +<para> +GLOC returns the address of the video display RAM as an integer number. +This address may be used in subsequent PEEK and POKE +operations to access the video display directly. GLOC can be used +to create special functions that are not available in the Graphics +Module. +</para> +<bridgehead renderas="sect2">GCOLR</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Gcolr",Colour)</command><sbr> +<command>RUN GFX("Gcolr",X,Y,Colour)</command> +</cmdsynopsis> +<para> +GCOLR is used to read the colour of the pixel at the current +graphics cursor position, or from the coordinates X,Y. The +parameter "Colour" may be an integer or a byte variable in which the +colour code is returned. +</para> +<bridgehead renderas="sect2">JOYSTK</bridgehead> +<cmdsynopsis> +<command>Calling Syntax: RUN GFX("Joystk",Stick,Fire,X,Y)</command> +</cmdsynopsis> +<para> +JOYSTK returns the status of the specified joystick's Fire button, +and returns the X,Y position of the joystick. The Fire button may +be read as a BYTE, INTEGER, or a BOOLEAN value. Non-zero (TRUE) +means the button was pressed. The X,Y values returned may be BYTE +or INTEGER variables, and they will be in the range 0 to 63. The +Stick parameter may be BYTE or INTEGER, and should be 0 for +RIGHT, or 1 for LEFT, depending on whether the RIGHT or the LEFT +joystick is to be tested. +</para> +<para> +Example: +<programlisting> +RUN GRX("Joystk",1,leftfire,leftx,lefty) +</programlisting> +</para> +<bridgehead renderas="sect1">A Sample Graphics Program</bridgehead> +<para> +The program on the next page illustrates how the GFX module is +called and used. It creates an analog clock on the graphics +display. +</para> +<para> +<programlisting> +PROCEDURE clk + 0000 (* Simple Clock Simulator *) + 001C DIM time(4),last(4),xx(3),yy(3):INTEGER + 0043 DIM x0,y0,radius,bkg:INTEGER + 0056 DIM i,j,x1,y1,x2,y2:INTEGER + 0071 DEG + 0073 bkg=0 + 007A x0=128 + 0081 y0=96 + 0088 radius=95 + 008F RUN GFX("MODE",1,bkg+1) + 00A5 RUN GFX("CLEAR") + 00B2 RUN GFX("CIRCLE",x0,y0,radius) + 00CF FOR i=0 to 89 STEP 6 + 00E4 x2=SIN(i)*radius + 00F4 y2=COS(i)*radius + 0104 x1=x2*.9 + 0115 y1=y2*.9 + 0126 j=MOD(i/30,3)+bkg+1 + 013B RUN GFX("LINE",x0+x1,y0+y1,x0+x2,y0+y2,j) + 016C RUN GFX("LINE",x0-x1,y0-y1,x0-x2,y0-y2,j) + 019D RUN GFX("LINE",x0+y1,y0-x1,x0+y2,y0-x2,j) + 01CE RUN GFX("LINE",x0-y1,y0+x1,x0-y2,y0+x2,j) + 01FF NEXT i + 020A FOR i=1 TO 3 + 021A time(i)=0 + 0225 xx(i)=x0 + 0231 yy(i)=y0 + 023D NEXT i + 0248 LOOP + 024A time$=DATE$ + 0250 last=time + 0258 time(3)=VAL(MID$(time$,16,2))*6 + 026E time(2)=VAL(MID$(time$(13,2))*6 + 0284 time(1)=MOD(VAL(MID$(time$,10,2))*30+time/2)/12,360) + 02A9 j=last(3) + 02B3 FOR i=3 TO 1 STEP -1 + 02C9 IF i=3 OR j=0 OR ABS(time(i)-last(i+1))<6 OR + ABS(time(i)-j)<6 THEN + 0300 RUN GFX("LINE",x0,y0,xx(i),yy(i),bkg) + 032B xx(i)=x0+SIN(time(i))*radius*(.3+i*.2) + 035A yy(i)=y0+COS(time(i))*radius*(.3+i*.2) + 0389 RUN GFX("LINE",x0,y0,xx(i),yy(i),bkg+i) + 03B7 ENDIF + 03B9 NEXT i + 03C4 WHILE time$=DATE$ DO + 03CF ENDWHILE + 03D3 ENDLOOP +</programlisting> +</para> + +</appendix> + +</book>
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/docs/basic09/makefile Sat Apr 06 13:34:58 2002 +0000 @@ -0,0 +1,19 @@ +OBJ=basic09 +STYLESHEET=docbook-utils.dsl + +all: book1.htm + +$(OBJ).pdf: $(OBJ).docbook $(STYLESHEET) + docbook2pdf -d $(STYLESHEET) $(OBJ).docbook + +$(OBJ).ps: $(OBJ).docbook $(STYLESHEET) + docbook2ps -d $(STYLESHEET) $(OBJ).docbook + +book1.htm: $(OBJ).docbook $(STYLESHEET) + rm -f *.htm *.html +# jade -t sgml -V html-index -d /usr/share/sgml/docbook/dsssl-stylesheets-1.64/html/docbook.dsl $(OBJ).docbook +# collateindex.pl -p -o index.docbook HTML.index + docbook2html -d $(STYLESHEET) $(OBJ).docbook + +print: + psnup -2 $(OBJ).ps | lpr