view docs/basic09/basic09.docbook @ 2437:d26e96c40194

rfm changes
author aaronwolfe
date Wed, 24 Feb 2010 00:37:08 +0000
parents 958740284209
children
line wrap: on
line source

<?xml version="1.0" ?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
   "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
  <!ENTITY b09           "BASIC09">
  <!ENTITY CPU           "6809">
  <!ENTITY os9level      "OS-9 Level One">
  <!ENTITY os9version    "Version 02.01.01 BETA1">
  <!ENTITY vendor        "The CoCo Community">
  <!ENTITY make          "TRS-80/Tandy Color Computer">
  <!ENTITY mdash          "&#8212;">
  <!ENTITY gfxapp       SYSTEM "gfx.appendix">
  <!ENTITY gfx2app      SYSTEM "gfx2.appendix">
]>
<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>Microware Systems Corporation.
All Rights Reserved.
Basic09 is a trademark of Microware Systems Corporation and Motorola Inc.
</holder>

</copyright>
<revhistory>
<revision>
<revnumber>A</revnumber>
<date>March 2003</date>
<revremark>Updated for OS-9 Level One Version 02.01.01</revremark>
</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 &CPU; Advanced Microprocessor
used by the &make;.
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 <emphasis>programming system</emphasis> 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 &make; Color
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 &CPU;
microprocessor to efficiently run high-level languages. &b09;
was developed at the same time as the &CPU; under the auspices of the
architects of the &CPU;. 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, <emphasis>&b09; always takes the
first character of every line as an edit command.</emphasis>
Some of the basic edit commands are:
<programlisting>
&lt;space> &lt;program statement> &lt;cr>  insert line
? &lt;cr>  go to next line down (just &lt;cr> also does the same)
- &lt;cr>  move back to previous line
L &lt;cr>  list current line
d &lt;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 &lt;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
----------       ------------         ------------
|        |       |          |         | +        |
|        |       |  $       |         | -        |
|        | &lt;-----+--&lt;eof>   |         | &lt;cr>     |
|        | &lt;-----+--BYE     |         | &lt;line#>  |
|        |       |  CHD     |         | &lt;space>  |
|        |       |  CHX     |         | c        |
|        |       |  DIR     |         | d        |
|        |       |  EDIT----+-------> | l        |
|        |       |  KILL    | &lt;-------+-q        |
|        |       |  LIST    |         | r        |       ------------
|BASIC09-+-----> |  LOAD    |         | s        |       | TRON     |
|        |       |  MEM     |         ------------       | TROFF    |
|        |       |  PACK    | &lt;--------------------------+ END or Q |
|        |       |  RENAME  |                            | DEG/RAD  |
|        |       |  RUN-----+-------> ------------       | STATE    |
|        |       |  SAVE    | &lt;-------+-END      |       | $        |
|        |       |          | &lt;-------+-&lt;CTRL Q> |       | BREAK    |
|        |       ------------ &lt;-------+-STOP     | &lt;-----+-CONT     |
|BASIC09 |                            | PAUSE----+-----> | DIR      |
|AUTORUN-+--------------------------> | ERROR----+-----> | LET      |
|        |                            | &lt;CTRL C>-+-----> | LIST     |
|        | &lt;--------------------------+-BYE      |       | PRINT    |
|        |                            | PROGRAM  | &lt;-----+-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 &mdash; 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>&lt;procname></entry>
<entry>means a procedure name</entry>
</row>
<row>
<entry>&lt;pathlist></entry>
<entry>An OS-9 file name</entry>
</row>
<row>
<entry>&lt;number></entry>
<entry>A decimal or hex number</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</para>
<sect1>
<title>System Mode Commands</title>
<para>
<cmdsynopsis>
<command>$ [&lt;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&amp;                 Calls the assembler as a <emphasis>background</emphasis> task
B: $basic09 fourier(20)&amp;            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 &lt;pathlist> or CHX &lt;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 [&lt;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 [&lt;procname>]</command>
<sbr/>
<command>E [&lt;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 [&lt;procname> {,&lt;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 [&lt;procname> {,&lt;procname>}] [> &lt;pathlist>]</command>
<sbr/>
<command>LIST* [&lt;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 &lt;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 [&lt;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 [&lt;procname> {,&lt;procname>}] [> &lt;pathlist>]</command>
<sbr/>
<command>PACK* [&lt;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 <emphasis>cannot</emphasis> 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.
<emphasis>The resulting file cannot be loaded into the workspace later on,</emphasis>
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 &lt;procname>,&lt;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 [&lt;procname> [ ( &lt;expr> , {&lt;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 [&lt;procname> { &lt;procname>} [> &lt;pathlist>]]</command>
<sbr/>
<command>SAVE* [&lt;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>&lt;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>&lt;space> &lt;text></entry>
<entry>insert unnumbered line</entry>
</row>
<row>
<entry>&lt;line#> &lt;text></entry>
<entry>insert or replace numbered line</entry>
</row>
<row>
<entry>&lt;line#> &lt;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>&lt;line#> &lt;text></entry>
<entry>insert or replace numbered line</entry>
</row>
<row>
<entry>&lt;line#> &lt;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 [ &lt;beg line #>  [,&lt;incr> ] ] &lt;CR>
r*[ &lt;beg line #>  [,&lt;incr> ] ] &lt;CR>
</programlisting>

The first format renumbers the program starting at the current line and
forward. Lines are renumbered using
&lt;beg line#> as the initial line number. &lt;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 &lt;beg line#> and/or &lt;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>- &lt;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>+ &lt;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>
&lt;CR>
+ &lt;CR>
+1 &lt;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 [&lt;number>] &lt;CR>
d*
</programlisting>

The first form deletes the &lt;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 <emphasis>before</emphasis> 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 [&lt;number>] &lt;CR>
l*
</programlisting>
The first form will display the &lt;number> of lines starting at the current
edit pointer position. If the number is <emphasis>negative</emphasis>, 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 &mdash; 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 &lt;delim> &lt;match str> [&lt;delim>] &lt;CR>
s*&lt;delim> &lt;match str> [&lt;delim>] &lt;CR>
</programlisting>

The first format searches for the &lt;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: "&lt;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 &lt;delim> &lt;match str> &lt;delim> &lt;repl str> [&lt;delim>] &lt;CR>
c*&lt;delim> &lt;match str> &lt;delim> &lt;repl str> [&lt;delim>] &lt;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 &lt;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>$ &lt;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 &lt;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 [&lt;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 &lt;var> := &lt;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 [#&lt;expr>,] [USING &lt;expr>,] &lt;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 [&lt;number>]   or   &lt;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| &lt;- 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 &lt;>), 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 <emphasis>not</emphasis> 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 TRUE 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 &lt; 100
</programlisting>
</informalexample>

The "&lt;" 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>&lt;> or >&lt;</entry>
<entry>Not equal to</entry>
<entry>ANY</entry>
<entry>BOOLEAN</entry>
</row>
<row>
<entry>&lt;</entry>
<entry>Less than</entry>
<entry>NUMERIC, STRING*</entry>
<entry>BOOLEAN</entry>
</row>
<row>
<entry>&lt;= or =&lt;</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 &lt; 1 &lt; ... &lt; 9 &lt; A &lt; B&lt; ... &lt; Z &lt; a &lt; b&lt;
... &lt; 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>&lt;</entry>
<entry>&lt;></entry>
<entry>=</entry>
<entry>>=</entry>
<entry>&lt;=</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>&lt;num></entry>
<entry>means any numeric-result expression.</entry>
</row>
<row>
<entry>&lt;str></entry>
<entry>means any string-result expression.</entry>
</row>
<row>
<entry>&lt;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(&lt;num>)</entry>
<entry>trigonometric sine of &lt;num></entry>
</row>
<row>
<entry>COS(&lt;num>)</entry>
<entry>trigonometric cosine of &lt;num></entry>
</row>
<row>
<entry>TAN(&lt;num>)</entry>
<entry>trigonometric tangent of &lt;num></entry>
</row>
<row>
<entry>ASN(&lt;num>)</entry>
<entry>trigonometric arcsine of &lt;num></entry>
</row>
<row>
<entry>ACS(&lt;num>)</entry>
<entry>trigonometric arcosine of &lt;num></entry>
</row>
<row>
<entry>ATN(&lt;num>)</entry>
<entry>trigonometric arctangent of &lt;num></entry>
</row>
<row>
<entry>LOG(&lt;num>)</entry>
<entry>natural logarithm (base e) of &lt;num></entry>
</row>
<row>
<entry>LOG10(&lt;num>)</entry>
<entry>logarithm (base 10) of &lt;num></entry>
</row>
<row>
<entry>EXP(&lt;num>)</entry>
<entry>e (2.71828183) raised to the power &lt;num>, which must be a
positive number</entry>
</row>
<row>
<entry>FLOAT(&lt;num>)</entry>
<entry>&lt;num> converted to type REAL (from BYTE or INTEGER)</entry>
</row>
<row>
<entry>INT(&lt;num>)</entry>
<entry>truncates all digits to the right of
the decimal point of a REAL &lt;num></entry>
</row>
<row>
<entry>PI</entry>
<entry>the constant 3.14159265.</entry>
</row>
<row>
<entry>SQR(&lt;num>)</entry>
<entry>square root of &lt;num>, which must be positive.</entry>
</row>
<row>
<entry>SQRT(&lt;num>)</entry>
<entry>square root of &lt;num>; same as SQR.</entry>
</row>
<row>
<entry morerows="2">RND(&lt;num>)</entry>
<entry>if &lt;num>=0, returns random x, 0 &lt;= x &lt; 1.</entry>
</row>
<row>
<entry>if &lt;num>>0, returns random x, 0 &lt;= x &lt; &lt;num>.</entry>
</row>
<row>
<entry>if &lt;num>&lt;0, use ABS(&lt;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(&lt;num>)</entry>
<entry>absolute value of &lt;num></entry>
</row>
<row>
<entry>SGN(&lt;num>)</entry>
<entry>signum of &lt;num>: -1 if &lt;num> &lt; 0; 0 if &lt;num> = 0; or 1 if &lt;num> > 0</entry>
</row>
<row>
<entry>SQ(&lt;num>)</entry>
<entry>&lt;num> squared</entry>
</row>
<row>
<entry>VAL(&lt;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(&lt;num>)</entry>
<entry>round REAL &lt;num> and convert to type INTEGER.</entry>
</row>
<row>
<entry>MOD(&lt;num1>,&lt;num2>)</entry>
<entry>modulus (remainder) function. &lt;num1> mod &lt;num2>.</entry>
</row>
<row>
<entry>ADDR(&lt;name>)</entry>
<entry>absolute memory address of variable, array, or structure named &lt;name>.</entry>
</row>
<row>
<entry>SIZE(&lt;name>)</entry>
<entry>storage size in bytes of variable, array, or structure named &lt;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(&lt;int>)</entry>
<entry>value of byte at memory address &lt;int>.</entry>
</row>
<row>
<entry>POS</entry>
<entry>current character position of PRINT buffer.</entry>
</row>
<row>
<entry>ASC(&lt;str>)</entry>
<entry>numeric value of first character of &lt;str>.</entry>
</row>
<row>
<entry>LEN(&lt;str>)</entry>
<entry>length of string &lt;str>.</entry>
</row>
<row>
<entry>SUBSTR(&lt;str1>,&lt;str2>)</entry>
<entry>substring search: returns starting position of first occurrence of &lt;str1> in
&lt;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 <emphasis>not</emphasis> be confused
with the BOOLEAN-type operators.

<informaltable frame="none">
<tgroup cols="2">
<colspec colwidth="1.5in"/>
<tbody>
<row>
<entry>LAND(&lt;num>,&lt;num>)</entry>
<entry>Logical AND</entry>
</row>
<row>
<entry>LOR(&lt;num>,&lt;num>)</entry>
<entry>Logical OR</entry>
</row>
<row>
<entry>LXOR(&lt;num>,&lt;num>)</entry>
<entry>Logical EXCLUSIVE OR</entry>
</row>
<row>
<entry>LNOT(&lt;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$(&lt;int>)</entry>
<entry>ASCII char. equivalent of &lt;int></entry>
</row>
<row>
<entry>DATE$</entry>
<entry>date and time, format: "yy/mm/dd hh:mm:ss"</entry>
</row>
<row>
<entry>LEFT$(&lt;str>,&lt;int>)</entry>
<entry>leftmost &lt;int> characters of &lt;str>.</entry>
</row>
<row>
<entry>RIGHT$(&lt;str>,&lt;int>)</entry>
<entry>rightmost &lt;int> characters of &lt;str>.</entry>
</row>
<row>
<entry>MID$(&lt;str>,&lt;int1>,&lt;int2>)</entry>
<entry>middle &lt;int2> characters of &lt;str> starting at
character position &lt;int1>.</entry>
</row>
<row>
<entry>STR$(&lt;num>)</entry>
<entry>converts numeric type &lt;num> to displayable characters of type
STRING representing the number converted.</entry>
</row>
<row>
<entry>TRIM$(&lt;str>)</entry>
<entry>&lt;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(#&lt;num>)</entry>
<entry>End-of-file test on disk file path &lt;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] &lt;var> := &lt;expr></command>
<sbr/>
<command>[LET] &lt;var> = &lt;expr></command>
<sbr/>
<command>[LET] &lt;struct> := &lt;struct></command>
<sbr/>
<command>[LET] &lt;struct> = &lt;struct></command>
</cmdsynopsis>

</para>
<para>
This statement
 evaluates an expression and stores the result in &lt;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 &lt;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 &lt; 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 &lt;integer expr> , &lt;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 &lt;bool expr> THEN &lt;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 &lt; balance then 400
</programlisting>
</para>
</sect2>
<sect2><title>IF Statement: Type 2</title>
<para>
Syntax:
<cmdsynopsis>
<command>IF &lt;bool expr> THEN &lt;statements></command>
<sbr/>
<command>[ ELSE &lt;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 &lt; b THEN
  PRINT "a is less than b"
  PRINT "a:";a;" b:";b
ENDIF

IF a &lt; 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 &lt;var> = &lt;expr> TO &lt;expr> [ STEP &lt;expr> ]</command>
<sbr/>
<command>NEXT &lt;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 &lt;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 &lt;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 = min-1 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 &lt;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 &lt;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&lt;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&lt;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 &lt;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 &lt;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 &lt;= 10 THEN 100
UNTIL x>10

(* compute factorial: n! *)
temp := 1.
INPUT "Factorial of what number? ",n
REPEAT
  temp := temp * n
  n := n-1
UNTIL n &lt;= 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 &lt;bool expr> THEN &lt;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 &lt;= 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 &lt; 0 THEN
  PRINT "x became zero first"
ENDEXIT
  x := x-1
EXITIF y &lt; 0 THEN PRINT "y became zero first"
ENDEXIT
  y := y-1
ENDLOOP
</programlisting>
</informalexample>

</para></sect2>
<sect2><title>GOTO Statement</title>
<para>
Syntax:
<cmdsynopsis>
<command>GOTO &lt;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 &lt;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 &lt;int expr> GOTO &lt;line #> {,&lt;line #>}</command>
<sbr/>
<command>ON &lt;int expr> GOSUB &lt;line #> {,&lt;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 &lt;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 &lt;proc name> [ ( &lt;param> {,&lt;param>} ) ]</command>
<sbr/>
<command>RUN &lt;string var> [ ( &lt;param> {,&lt;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 &CPU; 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 &CPU; machine language module, and executes it
accordingly. If it is a &CPU; machine language module, &b09; executes a
JSR instruction to its entry point and the module is executed as &CPU;
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>
<screen>
+----------------------+         ^
|                      |         |
                          higher addresses

|  more parameters     |

|                      |
+----------------------+        ---
|                      |         |
|  size of 1st param   |         |
+  -  -  -  -  -  -  - +      4 bytes
|  addr  of 1st param  |         |
|                      |         |
+----------------------+        ---
|                      |         |
|  parameter count     |      2 bytes
|                      |         |
+----------------------+        ---
|                      |         |
|  return address      |      2 bytes
|                      |         |
+----------------------+        ---  &lt;- &CPU; Stack Pointer
                                        Register value
</screen>
</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 <xref linkend="sample-programs"/>.
</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 &lt;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 <emphasis>must</emphasis> 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 &lt;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 &lt;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&amp;"       concurrent execution

SHELL "edit document"             calling text editor

SHELL "asm source o=obj ! spool &amp;"        concurrent assembly

N:=5
SHELL "kill "+STR$(N)

file$ := "/d1/batch_jobs"         concurrent execution of a
SHELL file$ + " -p >/p &amp;"       batch procedure file
</programlisting>
</informalexample>
</para></sect2>
<sect2><title>END Statement</title>
<para>
Syntax:
<cmdsynopsis>
<command>END [&lt;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 [&lt;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(&lt;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 [&lt;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>
&lt;output> BREAK IN PROCEDURE &lt;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 &lt;str expr></command>
<sbr/>
<command>CHX &lt;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 &lt;chars></command>
<sbr/>
<command>(* &lt;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 &lt;decl seq> {; &lt;decl seq>}</command>
<sbr/>
<command>&lt;decl seq> := &lt;decl> {, &lt;decl>} : &lt;type>}</command>
<sbr/>
<command>&lt;decl> := &lt;name> [, &lt;subscript> ]</command>
<sbr/>
<command>&lt;subscr> := ( &lt;const> [,&lt;const> [,&lt;const>]] )</command>
<sbr/>
<command>&lt;type> := BYTE | INTEGER | REAL | BOOLEAN |
 STRING | STRING &lt;max len> | &lt;user defined type></command>
<sbr/>
<command>&lt;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 :&lt;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 := index-1
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 <emphasis>does not check type</emphasis>. 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 &lt;type decl> {; &lt;type decl>}</command>
<sbr/>
<command>&lt;type decl> := &lt;field name> . &lt;decl> : &lt;type>}</command>
<sbr/>
<command>&lt;decl> := &lt;name> [, &lt;subscript> ]</command>
<sbr/>
<command>&lt;subscript> := ( &lt;const> [,&lt;const> [,&lt;const>]] )</command>
<sbr/>
<command>&lt;type> := BYTE | INTEGER | REAL | BOOLEAN |
 STRING | STRING [&lt;max len>] | &lt;user defined></command>
<sbr/>
<command>&lt;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
&mdash; 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 [#&lt;int expr>,] ["&lt;prompt>",] &lt;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 <xref linkend="sample-programs"/>.
</para></sect2>
<sect2><title>PRINT Statement</title>
<para>
Syntax:
<cmdsynopsis>
<command>PRINT &lt;output list></command>
<sbr/>
<command>PRINT #&lt;int expr>, &lt;output list></command>
<sbr/>
<command>PRINT USING &lt;str expr>, &lt;output list></command>
<sbr/>
<command>PRINT #&lt;int expr>, USING &lt;str expr>, &lt;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 80-character line of all dashes *)
REPEAT
  PRINT "-";
UNTIL POS >= 80
PRINT
</programlisting>
</informalexample>

</para></sect2>
<sect2><title>OPEN Statement</title>
<para>
Syntax:
<cmdsynopsis>
<command>OPEN #&lt;int var>,"&lt;str expr>" [ : &lt;access mode> ]</command>
<sbr/>
<command>&lt;access mode> := &lt;mode> ! &lt;mode> + &lt;access mode></command>
<sbr/>
<command>&lt;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 <emphasis>not</emphasis> 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 #&lt;int var>,"&lt;str expr>" [ : &lt;access mode> ]</command>
<sbr/>
<command>&lt;access mode> := &lt;mode> ! &lt;mode> + &lt;access mode></command>
<sbr/>
<command>&lt;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 #&lt;int expr> {,#&lt;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 &lt;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 #&lt;int expr num>,&lt;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 &lt;= result &lt;= 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 #&lt;int expr>,&lt;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 #&lt;int expr num>,&lt;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 #&lt;expr>,&lt;struct name></command>
<sbr/>
<command>PUT #&lt;expr>,&lt;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(&lt;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 &lt;input list></command>
<sbr/>
<command>DATA &lt;expr> , { &lt;expr> }</command>
<sbr/>
<command>RESTORE [ &lt;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 [&lt;expr#>,] USING &lt;str expr> , &lt;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. <emphasis>Blanks are not allowed in format strings!</emphasis>
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 <emphasis>and</emphasis> "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 &lt;= w &lt;= 255</entry>
</row>
<row>
<entry>f</entry>
<entry>Fraction field</entry>
<entry>1 &lt;= w &lt;= 9</entry>
</row>
<row>
<entry>j</entry>
<entry>OPTIONAL justification</entry>
<entry>&lt; (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>&lt;</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&lt;",5678.123          5678.12
PRINT USING "R8.2>",12.3                   12.30
PRINT USING "R8.2&lt;",-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 "&lt;" and "&gt;" 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>&lt;</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&lt;",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>&lt;</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>&lt;</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&lt;","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 <emphasis>not</emphasis> 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 &CPU;'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 &CPU; 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 <emphasis>much</emphasis> 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 <emphasis>inside</emphasis> the loop
may be executed many times for each single execution <emphasis>outside</emphasis> 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 id="pack" xreflabel="PACK"><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 &CPU; 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 id="sample-programs">
<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&lt;>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 increasingly-close 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(trial-desired)&lt;ABS(last-desired) THEN
      PRINT n; "/"; m; " = "; trial,
      PRINT "difference = "; trial-desired;
      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&lt;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(n-1,from,other,to_)
    PRINT "move #"; n; " from "; from; " to "; to_
    RUN hanoi(n-1,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:=x-value
    ENDWHILE

    IF x>=value-svalu THEN
      PRINT MID$(subs,i,1); MID$(char,i,1);
      x:=x-value+svalu
    ENDIF

  NEXT i
  END
</programlisting>

<programlisting>
PROCEDURE eightqueens
  REM originally by N. Wirth; here re-coded 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(n-h+7) AND down(n+h) THEN
      (* set queen on square [n,h] *)
      x(n):=h
      col(h):=FALSE \up(n-h+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:=n-1
      col(h):=TRUE \up(n-h+7):=TRUE \down(n+h):=TRUE
    ENDIF
    h:=h+1
  UNTIL h=8
  END
</programlisting>

<programlisting>
PROCEDURE electric
     REM re-programmed from "ELECTRIC"
     REM by Dwyer and Critchfield
     REM Basic and the Personal Computer (Addison-Wesley, 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 0-50,0-50 (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*x-a(i))+SQ(yscale*y-b(i)))
       EXITIF r=.0 THEN
         v:=99999.
       ENDEXIT
       v:=v+c(i)/r
     NEXT i
     RETURN

20   IF z&lt;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 post-inc instruction
      btemp:=d(n)&lt;d(top)
      n:=n+1
    UNTIL NOT (btemp)
    n:=n-1 \REM point at the tested element
    EXITIF n=m THEN
    ENDEXIT

    REPEAT  \REM this is a post-dec instruction
      m:=m-1
    UNTIL d(m)&lt;=d(top) OR m=n
    EXITIF n=m THEN
    ENDEXIT

    RUN exchange(d(m),d(n))
    n:=n+1 \REM prepare for post-inc
    EXITIF n=m THEN
    ENDEXIT

  ENDLOOP

  IF n&lt;>top THEN
    IF d(n)&lt;>d(top) THEN
      RUN exchange(d(n),d(top))
    ENDIF
  ENDIF

  IF bot&lt;n-1 THEN
    RUN qsort1(bot,n-1,d)
  ENDIF
  IF n+1&lt;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) &lt;> 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 &lt; 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)&lt;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 ultra-precision number: ",b$
  n:=SUBSTR(".",b$)

  IF n&lt;>0 THEN
    a(5):=VAL(MID$(b$+"0000",n+1,4))
    b$:=LEFT$(b$,n-1)
  ELSE a(5):=0
  ENDIF

  b$:="00000000000000000000"+b$
  n:=1+LEN(b$)
  FOR i=4 TO 1 STEP -1
    n:=n-4
    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+offset-1
        PRINT USING "h4,' - ',h2",modloc,buffer(offset);
        INPUT ":",rewrite
      EXITIF rewrite="" THEN ENDEXIT
        IF rewrite&lt;>" " 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=loc-65536.
  ENDWHILE
  FOR j=1 TO 16
    PRINT USING "h4",FIX(INT(loc))+(j-1)*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=nextchar-128
    ENDIF
    IF nextchar&lt;32 OR nextchar>125 THEN
      ascii=ascii+" "
    ELSE
      ascii=ascii+CHR$(nextchar)
    ENDIF
  NEXT i
  PRINT "  "; ascii;
</programlisting>

<programlisting>
     PROCEDURE MakeProc
     (* Generates an OS-9 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&lt;>"" 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&lt;>"" THEN
         Function=TRIM$(response)
       ENDIF
       INPUT "Redirect Input? ",response
       IF response="y" OR response="Y" THEN
	    ReInput="&lt;" \ 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&lt;>"" 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&lt;=i AND MID$(DirLine,j,1)&lt;>" " DO
	       j=j+1
	     ENDWHILE
	     FileName=MID$(DirLine,k,j-k)
	     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&lt;>"" THEN
		 ProcLine=ProcLine+" "+ReOutput+DestDir+"/"+FileName
	       ENDIF
	       ProcLine=ProcLine+" "+Options
	       WRITE #ProcPath,ProcLine
	     ENDIF
	     WHILE j&lt;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&lt;>"" THEN
	 WRITE #ProcPath,"Dir e "+DestDir
       ENDIF
       CLOSE #DirPath
       CLOSE #ProcPath
       SHELL "del procmaker...dir"
       PRINT
       INPUT "Another ? ",response
     UNTIL response&lt;>"Y" AND response&lt;>"y"
     IF response&lt;>"B" AND response&lt;>"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>&lt;cr></entry>
<entry>c*</entry>
<entry>l*</entry>
<entry>r*</entry>
</row>
<row>
<entry>+*</entry>
<entry>&lt;line #></entry>
<entry>d</entry>
<entry>q</entry>
<entry>s</entry>
</row>
<row>
<entry>-</entry>
<entry>&lt;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>&lt;</entry>
<entry>&lt;></entry>
<entry>=</entry>
<entry>>=</entry>
<entry>&lt;=</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>


&gfxapp;
&gfx2app;
</book>