Jaap's Psion II Page

Home / Psion / Technical Reference Manual / Chapter 17
                                CHAPTER 17

                                 ________
                                 LANGUAGE



      ____________
17.1  INTRODUCTION


The Organiser Programming Language (OPL) is a high level language which has
developed from a number of other languages:

                C
                ARCHIVE (The database module in Xchange)
                BASIC
                FORTH
                PL1

The language is designed to be:

                Fast
                Compact
                Flexible
                Accurate
                Extensible
                Simply overlayed

The language is stack based; all code is held  on  the  stack  as  are  all
intermediate  results.  To achieve speed the source code is translated into
an intermediate code (Q code) before it is run.



      ___________
17.2  DEFINITIONS

        _________
17.2.1  VARIABLES


All variables in OPL are held in one of three forms:

                Integer
                Floating pointing
                String

All this can either be simple variables or field variables.

All variables are zeroed when declared by a LOCAL, GLOBAL, OPEN  or  CREATE
statements.



        __________
17.2.2  PROCEDURES


OPL is a procedure base language, a number of  procedures  normally  go  to
make  up a program.  Up to 16 parameters can be passed to a procedure which
always returns a variable.

When a procedure is called a header is placed on  the  stack,  followed  by
space  for  variables  declared  and  the  Q code itself.  When a procedure
returns all the stack is freed for use by other  procedures.   This  allows
overlaying  of code so that programs can run which are substantially bigger
than the available memory on the machine.



        __________
17.2.3  PARAMETERS


Parameters passed to a procedure may be integer, floating point or  string.
They  are  passed  by value.  On the stack they are in reverse order to the
order they are input.

For  example  the  statement  "PROC:(12,17.5,"ABC")"  will   generate   the
following stack entry before the procedure PROC is called:

high memory      00 12
                00                      ; Integer type
                00 00 00 00 50 17 01 00
                01                      ; Floating point type
                03 41 42 43             ; "ABC"
                02                      ; String type
low memory      03                      ; Parameter count



        _________
17.2.4  ADDRESSES


Memory addresses in OPL are held as integers.  Pack addresses are held in 3
bytes.  In the CM operating system the most significant byte is ignored.



        ________
17.2.5  INTEGERS


An integer is a number between 32767 and -32768.  It is stored in memory as
a  single word.  In the source code of the language an integer may be input
in hexadecimal by preceding the number by a '$', so $FFFF is a valid number
and equal to -1.  A number in an OPL program will be taken as integer if it
is in the integer range with the  one  exception,  -32768  is  taken  as  a
floating point number.

The reason for this is that the translator translates a negative number  as
the  absolute  value, followed by a unary minus operator.  32768 is outside
the range for integers and so is translated as a floating point number.   A
small increase in speed and compactness can be obtained by writing negative
integers in hexadecimal.

It is very important to anticipate what is taken as integer.  For example:

        30001/2 is the integer 15000
but
        40001/2 is floating point number 20000.5.

To ensure that a number is taken as a floating  point  number  just  add  a
trailing period.  '2' is an integer, '2.' is a floating point number.

The calculator translates numbers as floating point.  If you wish to put an
integer  into  the  calculator  you  must  use  the  function INT.  So, for
example, from the calculator:

                PRICE:(INT(10))

passes the integer 10 to the procedure PRICE.



        ______________
17.2.6  FLOATING POINT


Floating point numbers are in the range  +/-9.99999999999E99  to  +/-1E-99.
They  are  held  in  Binary Coded Decimal (BCD) in 8 bytes; 6 bytes for the
mantissa, 1 byte for the exponent, and 1 for the sign.

The decimal number -153 is held as:

                00 00 00 00 30 15 02 80

where the last byte is the sign byte (either 00 or 80)  and  the  preceding
byte the exponent.

The decimal number .0234567 is held as:

                00 00 00 67 45 23 FE 00.

It is possible for the exponent to go out of range, e.g. 1E99*10 or 1E-99/10.
This is reported as an EXPONENT RANGE error.

When floating point numbers are translated they are held in a more  compact
form.   The first byte contains both the sign, in the most significant bit,
and the number of bytes following.  The  next  bytes  are  the  significant
bytes of the mantissa, the final byte is the exponent.

In Q code the decimal number -153 is represented as:

                83 30 15 02.

The decimal number .0234567 is represented as:

                04 47 45 23 FE

This compact form is always preceded by a QI_STK_LIT_NUM operator.



        _______
17.2.7  STRINGS


Strings are up to 255 characters long, with a preceding length  byte.   The
string "QWERTY" is held as:

                06 51 57 45 52 54 59

All string variables, except field strings, are preceded by that variable's
maximum length, as declared in the LOCAL or GLOBAL statement.

All strings in OPL have this format.   For  example  when  using  USR$  the
machine  code should return with the X register pointing at the length byte
of the string to be returned.



        ______
17.2.8  ARRAYS


One dimensional arrays are supported for integers, floating  point  numbers
and  strings.   Multi-dimensional arrays can be easily simulated by the use
of integer arithmetic.

Like all other variables, arrays are held on the stack.   In  the  case  of
string  arrays  the  maximum string length is the first byte, the next word
contains the array size, this is followed by data.  So, for example,

                LOCAL A$(5,3),B%(2),C(3)
                A$(4)="AB"
                C(1)=12345

initially sets up memory as follows (from low memory to high memory):

High memory     00 00 00 00             ; 5st element of A$()
                00 00 00 00             ; 4nd element of A$()
                00 00 00 00             ; 3rd element of A$()
                00 00 00 00             ; 2th element of A$()
                00 00 00 00             ; 1th element of A$()
                00 05                   ; array size of A$()
                03                      ; max string length of A$()
                00 00                   ; 2st element of B%()
                00 00                   ; 1st element of B%()
                00 02                   ; array size of B%()
                00 00 00 00 00 00 00 00 ; 3rd element of C()
                00 00 00 00 00 00 00 00 ; 2nd element of C()
                00 00 00 00 00 00 00 00 ; 1st element of C()
Low memory      00 03                   ; array size of C()

After running the procedure it looks like:

High memory     00 00 00 00             ; 5th element of A$()
                02 41 42 00             ; 4th element of A$()
                00 00 00 00             ; 3rd element of A$()
                00 00 00 00             ; 2nd element of A$()
                00 00 00 00             ; 1st element of A$()
                00 05                   ; array size of A$()
                03                      ; max string length of A$()
                00 00                   ; 2st element of B%()
                00 00                   ; 1st element of B%()
                00 02                   ; array size of B%()
                00 00 00 00 00 00 00 00 ; 3rd element of C()
                00 00 00 00 00 00 00 00 ; 2nd element of C()
                00 00 00 50 34 12 04 00 ; 1st element of C()
Low memory      00 03                   ; array size of C()


The string and array limits are inserted into the variable space  after  it
has been zeroed.  This process is referred to as "fixing up" the variables.

Only available memory limits the size of arrays.



        _______________
17.2.9  TYPE CONVERSION


Automatic type conversion takes place where possible.  For instance:

                A=10
and
                A=FLT(10)

produce exactly the same Q code.  Whereas:

                A=10.

has different Q code.  All three place the floating point  number  10  into
the variable A.

When expressions are evaluated the standard left to right rule  is  applied
with type integer being maintained as long as possible.  So, for example:

                A=1000*1000*1000.

generates an "INTEGER OVERFLOW" error.  But :

                A=1000.*1000*1000

does not.  This applies to any sub-expressions inside brackets, so:

                A=1000.*(1000*1000)

generates the overflow error.



         __________________
17.2.10  RECORDS AND FIELDS


A file consists of a file name record with a number  of  data  records.   A
record contains at least one character and at most 254 characters.

A record may contain up to 16 fields, delimited by the TAB character (ASCII
9).

Strings are held as the ASCII characters, numbers are  held  in  the  ASCII
form.  So for example after:

                OPEN "A:ABC",A,A%,B,C$
                A.A=12
                A.B=3.4
                A.C$="XYZ"

the file buffer contains:

                len      tab         tab
                0A 31 32 09 33 2E 34 09 58 59 5A.

When a file is opened the field names are given.  The field names and types
are not fixed and may be varied from OPEN to OPEN.  When a numeric field is
accessed the contents are converted  from  ASCII  to  integer  or  floating
point.   Should  this  conversion  fail  the  error  "STR  TO  NUM FAIL" is
reported.

When searching for a particular field the field name is  matched  with  the
field  name  buffer (see section 6.3.2) and the corresponding field split
out of the file buffer using UT$SPLT.

Note that any string can be assigned to a  string  field  but  that  if  it
includes a TAB character it will generate an extra field.  For example:
                OPEN "A:ABC",A,A$,B$,C$
                A.B$="Hello"
                A.A$="AB"+CHR$(9)+"CD"
                PRINT A.C$
                GET

will print "Hello" to the screen.  The file buffer contains:

                0B 41 42 09 43 44 09 48 65 6C 6C 6F

Saving data in ASCII is simple but it is easy to see how data can be
compressed by using BCD, hexadecimal or other techniques.




         ______________
17.2.11  VARIABLE SCOPE


When a procedure is loaded all the LOCALs and GLOBALs declared  in  it  are
allocated  space  on  the  stack.   This area is zeroed and the strings and
arrays are fixed up.  In other words, the maximum length of each string and
the array sizes are filled in.

These variables remain in memory at fixed locations, until execution of the
declaring  procedure  terminates.   LOCAL  variables are valid only in that
procedure, whereas GLOBAL variables are valid in all procedures  called  by
the declaring procedure.

See EXAMPLE 1 & 4.



         _________
17.2.12  EXTERNALS


If a variable used in a procedure is not declared LOCAL or GLOBAL  in  that
procedure it is taken as external.  The Q code contains a list of externals
and these are resolved at run time.

Using the frame  pointer,  RTA_FP  -  see  section  17.2.13,  the  previous
procedures are checked for all entries in the GLOBAL tables.  If a match is
found the variable address is inserted in  an  indirection  table.   If  an
external is not found it is reported as an error.

See EXAMPLE 4.

Note that neither the LOCAL names nor the parameter names  are  present  in
the Q code, but that GLOBAL names are.



         _________________
17.2.13  LANGUAGE POINTERS


There are three key pointers used by the language:

                RTA_SP          Language stack pointer
                RTA_PC          Program counter
                RTA_FP          Frame (procedure) pointer

RTA_SP points at the lowest byte  of  the  stack.   So  if  an  integer  is
stacked,  RTA_SP  is  decremented by 2 and the word is saved at the address
pointed to by RTA_SP.

RTA_PC points at the current operand/operator executed and  is  incremented
after  execution - except at the start of a procedure or a GOTO when RTA_PC
is set up appropriately.

RTA_FP points into the header of the current procedure.

Each procedure header has the form:

                        Device (zero if top procedure)
                        Return RTA_PC
                        ONERR address
                        BASE_SP
RTA_FP points at:       Previous RTA_FP
                        Start address of the global name table
                        Global name table
                        Indirection table for externals/parameters

This is followed by the variables, and finally by the Q code.

RTA_FP points at the previous RTA_FP, so it is easy to jump up through  all
the  procedures  above.   The  language  uses  this when resolving external
references and when handling errors.

See EXAMPLE 4.



         ________________
17.2.14  ADDRESSING MODES


Local variables and global variables declared in the current procedure  are
accessed  directly.  A reference to such variables is by an offset from the
current RTA_FP.

Parameters  and  externally  declared   global   variables   are   accessed
indirectly.   The  addresses of these variables are held in the indirection
table, the required address in this table is found by adding the offset  in
the Q code to the current RTA_FP.

See EXAMPLE 4.



         ________
17.2.15  TOP LOOP


Each procedure consists of two parts, a header and  Q  code.   The  Q  code
contains  all  the operands and operators in a table that is run by the TOP
LOOP.

The TOP LOOP controls the language, it performs the following functions:

Increment RTA_PC by the B register
Test for the ON/CLEAR key, see section 7.2.1
Test for low battery, see section 7.4.3
Load and execute the next operand/operator
Test carry - if set then initiate error handling



      ________
17.3  OPERANDS


Each operand stacks either a constant value or a pointer to a variable.

There are a number of types of operands.  Operands are  named  after  their
type, the types are:

Integer                                 INT
Floating point                  NUM
String                          STR
Constants (i.e. not variables)    CON
Arrays                          ARR
Simple (i.e. not array)           SIM
Offset from RTA_FP              FP
Indirect offset from RTA_FP     IND
Left side (i.e. assigns)          LS
Field                           FLD
Stack byte/word                 LIT
Refer to the fixed memories     ABS


Internal Name     Op + Bytes    Added to the stack
QI_INT_SIM_FP     $00   2       The integer
QI_NUM_SIM_FP     $01   2       The floating point number
QI_STR_SIM_FP     $02   2       The string

These operands take the following word,  add  it  to  RTA_FP  (see  section
17.2.13) and stack the variable at that address.

Internal Name     Op + Bytes    Stack
QI_INT_ARR_FP     $03   2       Drops element number, adds an integer
                                 from the array
QI_NUM_ARR_FP     $04   2       Drops element number, adds a floating
                                 point number from the array
QI_STR_ARR_FP     $05   2       Drops element number, adds a string
                                 from the array

These operands take the following word, adds it to RTA_FP to get the  start
of  the  array.   The  required element number is dropped off the stack and
checked against the maximum size of the array.  The address of the  element
is then calculated and the variable stacked.


Internal Name     Op + Bytes    Added to the stack
QI_NUM_SIM_ABS    $06   1       Floating point number

This operand gives access to the  calculators  memories,  M0  to  M9.   The
operand is followed by the offset to the memory required.


Internal Name     Op + Bytes    Added to the stack
QI_INT_SIM_IND    $07   2       The integer
QI_NUM_SIM_IND    $08   2       The floating point number
QI_STR_SIM_IND    $09   2       The string

These operands take the following word, add it to RTA_FP, load the  address
at that address and stack the variable at that address.


Internal Name     Op + Bytes    Stack
QI_INT_ARR_IND    $0A   2       Drops element number, adds the integer
                                 from the array
QI_NUM_ARR_IND    $0B   2       Drops element number, adds the
                                 floating point number from the array
QI_STR_ARR_IND    $0C   2       Drops element number, adds the string
                                 from the array

These operands take the following  word,  adds  it  to  RTA_FP,  loads  the
address  at that address to get the start of the array.  The element of the
array required is dropped off the stack, it is  then  checked  against  the
maximum  size  of the array.  The address of the element is then calculated
and the variable stacked.


Internal Name     Op + Bytes    Added to the stack
QI_LS_INT_SIM_FP  $0D   2       The address of the integer + field flag
QI_LS_NUM_SIM_FP  $0E   2       The address of the floating point
                                 number + field flag
QI_LS_STR_SIM_FP  $0F   2       The maximum size + the address of
                                 the string + field flag
QI_LS_INT_ARR_FP  $10   2       The address of the integer from the
                                 array + field flag
QI_LS_NUM_ARR_FP  $11   2       The address of the floating point
                                 number from the array + field flag
QI_LS_STR_ARR_FP  $12   2       The maximum size + the address of
                                 the string from the array + field flag
QI_LS_NUM_SIM_ABS $13   2       The address of the calculator memory +
                                 field flag
QI_LS_INT_SIM_IND $14   2       The address of the integer + field flag
QI_LS_NUM_SIM_IND $15   2       The address of the floating point
                                 number + field flag
QI_LS_STR_SIM_IND $16   2       The maximum size + the address of
                                 the string + field flag
QI_LS_INT_ARR_IND $17   2       The address of the integer from the
                                 array + field flag
QI_LS_NUM_ARR_IND $18   2       The address of the floating point number
                                 from the array + field flag
QI_LS_STR_ARR_IND $19   2       the maximum size + the address of the
                                 string from the array + field flag

These operands correspond to their right side equivalents.  In the case  of
strings  the  maximum  length  is  stacked  first.  Then, in all cases, the
address of the variable is stacked.  The field flag byte is  then  stacked,
in all these cases it is zero to show that it is not a field reference.

See EXAMPLE 1.


Internal Name     Op + Bytes    Stack
QI_INT_FLD        $1A   1       Drops the field name, adds the integer
QI_NUM_FLD        $1B   1       Drops the field name, adds the
                                 floating point number
QI_STR_FLD        $1C   1       Drops the field name, adds the string

These operands are followed by a logical file name, 0,1,2 or 3, which  says
which  logical file to use.  First it looks for the field name in the Field
Name Symbol Table.  If it is found the corresponding field  is  split  from
the corresponding File Buffer.

If it is a string it is immediately placed on the stack.  If it is  numeric
it is converted from ASCII to the relevant format and placed on the stack.


Internal Name     Op + Bytes    Stack
QI_LS_INT_FLD     $1D   1       Stacks the logical file name +
                                field flag
QI_LS_NUM_FLD     $1E   1       Stacks the logical file name +
                                field flag
QI_LS_STR_FLD     $1F   1       Stacks the logical file name +
                                field flag

These operands stacks the logical file, the byte following the operand, and
the field flag which in this case is non-zero.  All the work is done by the
assign.


Internal Name   Op + Bytes      Added to the stack
QI_STK_LIT_BYTE $20     1       The byte
QI_STK_LIT_WORD $21     2       The word

Stacks the  following  byte  or  word.   QI_STK_LIT_WORD  is  identical  to
QI_INT_CON.


Internal Name   Op + Bytes      Added to the stack
QI_INT_CON      $22     2       Integer
QI_NUM_CON      $23     *       Floating point number (see section 17.2.6)
QI_STR_CON      $24     *       String

Stacks the constant value following.



      _________
17.4  OPERATORS


Operators generally do things to the variables already on the stack.



        ____________________________
17.4.1  ERRORS, CALLS AND PARAMETERS


In the following section if an operand  cannot  return  an  error  then  no
errors are listed.

Any access to a device can result in the following  errors.   They  are  no
given explicitly as error for that operand/operator:

        ER_FL_NP - no pack
        ER_PK_IV - unknown pack
        ER_DV_CA - bad device name
and if the pack was not blank:
        ER_PK_NB - pack not blank

When writing to a pack the following are always possible:

        ER_FL_PF - pack full
        ER_PK_RO - read only pack
        ER_PK_DE - write error

If the operator calls an operating system then that is listed.  If no calls
are  given  then the run time code handles it all itself.  In general there
is no difference between call with a $ and with  an  _,  the  $  calls  are
called  through  SWIs  whereas the _ calls are made directly.  Direct calls
are faster, but SWIs can be redirected for the addition of extra  features.
See section 5.1.1 on calling system services.

If there is more than one  parameter  they  are  listed.   The  values  are
stacked  in order.  So para1 is stacked before para2 - when the operator is
called the last parameter is the one pointed to by the RTA_SP.



        ________________________________________
17.4.2  LOGICAL AND ARITHMETIC COMPARE OPERATORS

Internal Name   Op      Stack
QCO_LT_INT      $27     Drops 2 INTs, returns 0 or -1 as an INT
QCO_LTE_INT     $28     Drops 2 INTs, returns 0 or -1 as an INT
QCO_GT_INT      $29     Drops 2 INTs, returns 0 or -1 as an INT
QCO_GTE_INT     $2A     Drops 2 INTs, returns 0 or -1 as an INT
QCO_NE_INT      $2B     Drops 2 INTs, returns 0 or -1 as an INT
QCO_EQ_INT      $2C     Drops 2 INTs, returns 0 or -1 as an INT
QCO_ADD_INT     $2D     Drops 2 INTs, returns result as an INT
QCO_SUB_INT     $2E     Drops 2 INTs, returns result as an INT
QCO_MUL_INT     $2F     Drops 2 INTs, returns result as an INT
QCO_DIV_INT     $30     Drops 2 INTs, returns result as an INT
QCO_POW_INT     $31     Drops 2 INTs, returns result as an INT
QCO_UMIN_INT    $32     Drops an INT, returns result as an INT
QCO_NOT_INT     $33     Drops an INT, returns result as an INT
QCO_AND_INT     $34     Drops 2 INTs, returns result as an INT
QCO_OR_INT      $35     Drops 2 INTs, returns result as an INT

QCO_LT_NUM      $36     Drops 2 NUMs, returns 0 or -1 as an INT
QCO_LTE_NUM     $37     Drops 2 NUMs, returns 0 or -1 as an INT
QCO_GT_NUM      $38     Drops 2 NUMs, returns 0 or -1 as an INT
QCO_GTE_NUM     $39     Drops 2 NUMs, returns 0 or -1 as an INT
QCO_NE_NUM      $3A     Drops 2 NUMs, returns 0 or -1 as an INT
QCO_EQ_NUM      $3B     Drops 2 NUMs, returns 0 or -1 as an INT
QCO_ADD_NUM     $3C     Drops 2 NUMs, returns result as an NUM
QCO_SUB_NUM     $3D     Drops 2 NUMs, returns result as an NUM
QCO_MUL_NUM     $3E     Drops 2 NUMs, returns result as an NUM
QCO_DIV_NUM     $3F     Drops 2 NUMs, returns result as an NUM
QCO_POW_NUM     $40     Drops 2 NUMs, returns result as an NUM
QCO_UMIN_NUM    $41     Drops a NUM, returns result as an NUM
QCO_NOT_NUM     $42     Drops a NUM, returns 0 or -1 as an INT
QCO_AND_NUM     $43     Drops 2 NUMs, returns 0 or -1 as an INT
QCO_OR_NUM      $44     Drops 2 NUMs, returns 0 or -1 as an INT

QCO_LT_STR      $45     Drops 2 STRs, returns 0 or -1 as an INT
QCO_LTE_STR     $46     Drops 2 STRs, returns 0 or -1 as an INT
QCO_GT_STR      $47     Drops 2 STRs, returns 0 or -1 as an INT
QCO_GTE_STR     $48     Drops 2 STRs, returns 0 or -1 as an INT
QCO_NE_STR      $49     Drops 2 STRs, returns 0 or -1 as an INT
QCO_EQ_STR      $4A     Drops 2 STRs, returns 0 or -1 as an INT
QCO_ADD_STR     $4B     Drops 2 STRs, returns result as a STR

The compares drop whatever is on the stack and  return  an  integer  either
TRUE(-1) or FALSE(0).

NOT, AND, and OR are bitwise on INTs, but on NUMs they are logical.  So the
following equalities are true:

NOT(3.0) = 0;   (3.0 AND 5.0) = -1;     (3.0 OR 5.0) = -1;
NOT(3) = -4;    (3 AND 5) = 1;          (3 OR 5) = 7;

The string compares are case sensitive.

Divide by zero generates the error ER_FN_BA.


The function XY will generate ER_FN_BA if X zero and Y less than  or  equal
to  zero, X negative and Y non-integer.  NOTE VERY WELL:  In the calculator
all numeric constants are automatically converted to floating point.  So in
the calculator NOT(3) evaluates to 0, whereas NOT(INT(3)) is -4.

Note also:  Outside the calculator a simple number is taken as  an  integer
if  it  is  less  than 32768 and more than -32768, so in a procedure 10**10
gives an INTEGER OVERFLOW error.



      _________________
17.5  COMMAND OPERATORS

        ______
17.5.1  QCO_AT

Positions the cursor.

OP:     $4C
OPL:    AT
Para1:  New X position (1 to 16)
Para2:  New Y position (1 or 2)
Stack:  Drops the two integers on the stack
Calls:  DP$STAT
Errors: ER_FN_BA - Bad parameter if either parameter out of range.

Clears RTB_CRFL, the carriage return flag.



        ________
17.5.2  QCO_BEEP

Beeps with a frequency of 460800/(39+para2).

OP:     $4D
OPL:    BEEP
Para1:  Integer duration in milliseconds
Para2:  Integer period
Stack:  Drops the two integers
Calls:  BZ_TONE
Bugs:   If para1 is negative BEEP returns immediately.
        Para2 is regarded as an unsigned word.



        _________
17.5.3  QCO_BREAK

Break the execution of OPL.  Note that this is not equivalent  to  the  OPL
word BREAK.

OP:     $26
Calls:  UT_LEAV



        _______
17.5.4  QCO_CLS

Clears the screen.  The cursor is homed to the top left.

OP:     $4E
OPL:    CLS
Stack:  No effect
Calls:  DP_CLRB



        __________
17.5.5  QCO_CURSOR

Set the cursor on or off.

OP:     $4F
OPL:    CURSOR ON, CURSOR OFF
Stack:  No effect
Calls:  DP$STAT

Gets byte after operator, sets or clears most significant bit of DPB_CUST.



        __________
17.5.6  QCO_ESCAPE

Enables or disables the ON/CLEAR key freeze and quit.

OP:     $50
OPL:    ESCAPE ON, ESCAPE OFF
Stack:  Drops the integer on the stack

Gets byte after operator, sets or clears RTA_ESCF.



        ________
17.5.7  QCO_GOTO

Jump RTA_PC to a new location in the same procedure.

OP:     $51
OPL:    GOTO, BREAK, CONTINUE, ELSE
Stack:  No effect

Adds word after the operator to RTA_PC.  See QCO_BRA_FALSE.



        _______
17.5.8  QCO_OFF

Turns off the machine.  Does not terminate language execution.

OP:     $52
OPL:    OFF
Stack:  No effect
Calls:  BT_SWOF

This is exactly the same state as when the machine is turned off at the top
level.  The drain on the battery is minimal.  See section 5.4.



        _________
17.5.9  QCO_ONERR

Set up error handling.

OP:     $53
OPL:    ONERR, ONERR OFF
Stack:  No effect

The following word contains the offset to the address to  jump  to  in  the
event  of an error being detected.  ONERR OFF is the same operator followed
by a zero word.  The ONERR address is saved  in  the  header,  see  section
17.2.13.



         _________
17.5.10  QCO_PAUSE

If positive it pauses for that many 50 millisecond units,  if  negative  it
pauses for that many 50 millisecond units or until the first key press.  If
it is zero it waits for the next key press.

OP:     $54
OPL:    PAUSE
Stack:  Drops the integer
Bugs:   If a key is pressed it is not removed from the input buffer, so
        it should be read by a KEY or GET function.

Uses the 'SLP' processor instruction, so less power  is  used  when  PAUSEd
compared  to  normal  operation.  It does however use more power than being
switched off.  See section 3.2.



         _________
17.5.11  QCO_POKEB

Pokes a byte into memory.

OP:     $55
OPL:    POKEB
Para1:  Address to write to
Para2:  Byte to be written
Stack:  Drops the two integers
Errors: ER_FN_BA - Bad parameter

Reports an error if para2 is  not  a  byte.   If  the  address  is  in  the
protected range $00 to $3F or $282 to $400 then it does nothing.



         _________
17.5.12  QCO_POKEW

Pokes a word into memory.

OP:     $56
OPL:    POKEW
Para1:  Address to write to
Para2:  Word to be written
Stack:  Drops the two integers on the stack
Errors: ER_FN_BA - Bad parameter

If the address is in the protected range $00 to $3F or $282 to $400 then it
does nothing.



         _________
17.5.13  QCO_RAISE

Generates an error condition.

OP:     $57
OPL:    RAISE
Stack:  Drops the integer
Errors: ER_FN_BA - Bad parameter

If integer on the stack is not a byte it reports error.  Otherwise  it  has
exactly  the  same effect as if that error was generated.  Errors generated
by RAISE are handled in the normal way by ONERR.

Using this command and ONERR the programmer can  completely  take-over  the
handling and reporting of errors.

If the error is out of the range normally reported by the  OS  the  message
"*** ERROR ***" is reported.

RAISE 0 is special as it does not report an error.



         _____________
17.5.14  QCO_RANDOMIZE

Set the  seed  of  the  random  number  generator.   The  sequence  numbers
generated by RND becomes repeatable.

OP:     $58
OPL:    RANDOMIZE
Stack:  Drops the floating point number on the stack
Calls:  FN_RAND



         ___________
17.5.15  QCO_SPECIAL

Special operator used to vector to machine code.

OP:     $25
OPL:    See below
Stack:  No effect

Vectors via the contents of the location RTA_1VCT  to  machine  code.   The
machine code should return with the carry flag set to report an error.

If the ASCII value 1 is encountered in the OPL source code it is  taken  to
be  a  SPECIAL  call which returns an integer.  A 2 is for a floating point
return and 3 for a string.  It is impossible to get these values  into  the
source code from the editor, it must be generated by another program.

For example if you want to write an evaluator for  a  spreadsheet  and  you
want to add cell A1 to cell B1 you could poke in:

        01 ????



         ________
17.5.16  QCO_STOP

Stops executing the language.

OP:     $59
OPL:    STOP

Resets RTA_SP, zeroes the file buffers by calling AL_ZERO  and  leaves  the
language.



         ________
17.5.17  QCO_TRAP

Disables the reporting of any error  arising  from  the  execution  of  the
following  operator.   Instead  the error number is saved in RTB_EROR which
can be read by the function ERR.

OP:     $5A
OPL:    TRAP
Stack:  No effect

Clears RTB_EROR and sets the trap flag RTB_TRAP.

The following operators can be used with TRAP:

        APPEND          BACK            CLOSE
        COPY            CREATE          DELETE
        ERASE           EDIT            FIRST
        INPUT           LAST            NEXT
        OPEN            POSITION        RENAME
        UPDATE          USE

If no error occurs these operators clear RTB_TRAP.

Most of these are file-related operator.  The  programmer  will  frequently
either  need  to report errors arising from the operators himself or handle
them in a discriminating way.  For example:

                TRAP OPEN "B:XYZ",A,A$
                IF ERR
                 TRAP OPEN "C:XYZ",A,A$
                 IF ERR
                  CLS :PRINT "FILE XYZ NOT" :PRINT "FOUND"
                  BEEP 100,100 :GET :STOP
                 ENDIF
                ENDIF

INPUT and EDIT are different.  TRAP changes the conditions under which they
exit.   "EDIT  A$"  will  not exit on the ON/CLEAR key, "TRAP EDIT A$" will
exit with RTB_EROR set to ER_RT_BK.  When inputting a  number  without  the
TRAP  option,  the  routine  will  not  exit until a valid number is input;
however with TRAP any input will be accepted and  the  corresponding  error
condition placed in RTB_EROR.

See QCO_INPUT_INT, QCO_INPUT_NUM, QCO_INPUT_STR, QCO_EDIT.



      ____ _________
17.6  FILE OPERATORS

        __________
17.6.1  QCO_APPEND

Adds the current record buffer to the current file as a new record.

OP:     $5B
OPL:    APPEND
Stack:  No effect
Errors: ER_RT_FC - file not open
Calls:  FL$SETP, FL$RECT, FL$RSET, FL$WRIT
Bugs:   If the current length of the current record is zero, it is
        automatically made non-zero by adding a TAB, the field delimiter.

The contents of the file buffer are saved at the end of the current device.
The first byte of the buffer is the length of the buffer.



        _________
17.6.2  QCO_CLOSE

Closes the current file.

OP:     $5C
OPL:    CLOSE
Stack:  No effect
Errors: ER_RT_FC - file not open
Calls:  FL$SETP, FL$RECT, FL$RSET, AL$ZCEL
Bugs:   After closing the file it looks for another file to make current.
        If several files are open it is unpredictable which will
        become current.

CLOSE has no effect on the file itself, it checks that the  file  is  open,
clears the record type in RTT_FIL, and zeroes the two cells.



        ________
17.6.3  QCO_COPY

Copies a file from one device to another.  If the target already exists the
data is appended.

OP:     $5D
OPL:    COPY
Stack:  Drops the names of the two files
Errors: ER_FL_NX - file does not exist
        ER_PK_CH - changed pack
Calls:  fl$copy
Bugs:   You cannot copy to the same device.



        __________
17.6.4  QCO_CREATE

Creates a file.

OP:     $5E
OPL:    CREATE
Stack:  Drops the name of the file to be created
Errors: ER_FL_EX - file already exists
        ER_AL_NR - out of memory
Calls:  FL$CRET, AL$GROW, FL$SETP, FL$RECT, FL$RSET, FL$READ

See EXAMPLE 2.



        __________
17.6.5  QCO_DELETE

Deletes a file.

OP:     $5F
OPL:    DELETE
Stack:  Drops the name of the file to be deleted.
Errors: ER_FL_NX - file does not exist
        ER_RT_FO - file open
Calls:  FL$DELN

Checks that the file is not open.  Deletes all records, starting  with  the
first, and finally the file name record of the file.



        _________
17.6.6  QCO_ERASE

Erases the current record of the current file.

OP:     $60
OPL:    ERASE
Stack:  No effect
Errors: ER_RT_FC - file not open
        ER_FL_EF - end of file
Calls:  FL$ERAS, FL$SETP, FL$RECT, FL$RSET, FL$READ
Bugs:   The current record becomes the record following the erased record.
        If, after the erase, FL$READ returns an 'END OF FILE', the length
        of the current record is set to zero and the current record number
        set to the number of records (as found  by FL$SIZE) plus one.

        'END OF FILE' error will be generated if already at the end
        of the file. This includes the case of a file with no records.



        _________
17.6.7  QCO_FIRST

Goes to the first record of the current file.

OP:     $61
OPL:    FIRST
Stack:  No effect
Errors: ER_RT_FC - file not open
Calls:  FL$SETP, FL$RECT, FL$RSET, FL$READ
Bugs:   No error reported if there are no records.



        ________
17.6.8  QCO_LAST

Goes to the last record of the current file.

OP:     $62
OPL:    LAST
Stack:  No effect
Errors: ER_RT_FC - file not open
Calls:  FL$SIZE, FL$SETP, FL$RECT, FL$RSET, FL$READ
Bugs:   No error reported if there are no records.



        ________
17.6.9  QCO_NEXT

Goes to the next record.

OP:     $63
OPL:    NEXT
Stack:  No effect
Errors: ER_RT_FC - file not open
Calls:  FL$NEXT, FL$READ
Bugs:   No error reported if at the end of file.
        If FL$READ returns an "END OF FILE" error, the length of the
        current record is set to zero and the current record number set
        to the number of records (as found by FL$SIZE) plus one.



         ________
17.6.10  QCO_BACK

Steps back one record.

OP:     $64
OPL:    BACK
Stack:  No effect
Errors: ER_RT_FC - file not open
Calls:  FL$BACK
Bugs:   No error reported if already on the first record.



         ________
17.6.11  QCO_OPEN

Open a file.

OP:     $65
OPL:    OPEN
Stack:  Drop the name of the file.
Errors: ER_RT_FO - file open
Calls:  FL$OPEN, FL$SETP, FL$RECT, FL$RSET, FL$READ

OPEN has exactly the same form as CREATE.  See EXAMPLE 2.



         ____________
17.6.12  QCO_POSITION

Position at that record.

OP:     $66
OPL:    POSITION
Stack:  Drops the integer
Errors: ER_RT_FC - file not open
Calls:  FL$SETP, FL$RECT, FL$RSET, FL$READ
Bugs:   If the FL$READ returns an 'END OF FILE', the length of the current
        record is set to zero and the current record number set to the
        number of records (as found by FL$SIZE) plus one.



         __________
17.6.13  QCO_RENAME

Renames a file.

OP:     $67
OPL:    RENAME
Stack:  Drops the two file names
Errors: ER_RT_FO - file open
        ER_FL_NX - file exists
        ER_FL_NX - file does not exist
Calls:  FL$RENM

Erases the file name record and writes a new one.



         __________
17.6.14  QCO_UPDATE

Updates a record.

OP:     $68
OPL:    UPDATE
Stack:  No effect
Errors: ER_RT_FC - file not open
Calls:  FL$ERAS, FL$WRIT, FL$SETP, FL$RECT, FL$RSET, FL$READ
Bugs:   If the APPEND fails, with 'PAK FULL' for example, the original
        record is already erased.

It deletes the current record in the current  file  and  then  APPENDs  the
contents of the buffer.



         _______
17.6.15  QCO_USE

Changes the current file.

OP:     $69
OPL:    USE
Stack:  No effect
Errors: ER_TR_BL - bad logical name (logical name not in use)

Takes the byte following the operator and after checking it  makes  it  the
new current logical file.  See section 17.11.3.




      _______________
17.7  OTHER OPERATORS

        _________
17.7.1  QCO_KSTAT

Set the shift state of the keyboard.

OP:     $6A
OPL:    KSTAT
Stack:  Drops integer
Errors: ER_FN_BA - function argument error
Calls:  KB$STAT
Use KSTAT to change the upper/lower alpha/numeric case:
        1       alpha, upper case (default setting)
        2       alpha, lower case
        3       numeric, upper case
        4       numeric, lower case



        ________
17.7.2  QCO_EDIT

Edits a string.

OP:     $6B
OPL:    EDIT
Stack:  Drop the left side reference to string
Errors: ER_RT_BK - ON/CLEAR key pressed
        ER_RT_FC - file not open
        ER_RT_NF - field not found
        ER_RT_RB - record too big
Calls:  ED$EDIT

If the string to be edited is a field then the maximum length of the string
is  252.   Otherwise the maximum length allowed is the length of the string
as defined in the LOCAL or GLOBAL statement.  The string to  be  edited  is
copied  into  RTT_BUF.   Once  the  string  is edited it is assigned to the
source.

If the EDIT is preceded by TRAP then the edit will exit on the ON/CLEAR key
with the error condition ER_RT_BK.  The string remains unchanged.

Before execution of this  operator  RTB_CRFL  is  tested  and,  if  set,  a
carriage return is sent to the screen and the flag cleared.



        _____________
17.7.3  QCO_INPUT_INT

Input an integer.

OP:     $6C
OPL:    INPUT
Stack:  Drops the left side integer reference
Errors: ER_RT_BK - ON/CLEAR key pressed
        ER_MT_IS - conversion to number failed
        ER_RT_IO - integer overflow
        ER_RT_FC - file not open
        ER_RT_NF - field not found
        ER_RT_RB - record too big
Calls:  ED$EDIT

If the INPUT is preceded by TRAP then the input will exit on  the  ON/CLEAR
key  with  the  error  condition ER_RT_BK.  It will also exit if an invalid
integer is input, e.g. 99999 or $1.

If there is no TRAP then the INPUT will not exit on the  ON/CLEAR  key  and
invalid integers generate a '?' on the next line and the INPUT is repeated.

Up to 6 characters, including leading spaces, are allowed.

Before execution of this  operator  RTB_CRFL  is  tested  and,  if  set,  a
carriage return is sent to the screen and the flag cleared.



        _____________
17.7.4  QCO_INPUT_NUM

Inputs a floating point number.

OP:     $6D
OPL:    INPUT
Stack:  Drops left side reference to floating point number
Errors: ER_RT_BK - ON/CLEAR key pressed
        ER_MT_IS - conversion to number failed
        ER_RT_IO - integer overflow
        ER_RT_FC - file not open
        ER_RT_NF - field not found
        ER_RT_RB - record too big
Calls:  ED$EDIT

If the INPUT is preceded by TRAP then the input will exit on  the  ON/CLEAR
key  with  the  error  condition ER_RT_BK.  It will also exit if an invalid
floating point number is input, e.g. 999999999999999 or $1.

If there is no TRAP then the INPUT will not exit on the  ON/CLEAR  key  and
invalid integers generate a '?' on the next line and the INPUT is repeated.

Up to 15 characters, including leading spaces, are allowed.

Before execution of this  operator  RTB_CRFL  is  tested  and,  if  set,  a
carriage return is sent to the screen and the flag cleared.



        _____________
17.7.5  QCO_INPUT_STR

Inputs a string.

OP:     $6E
OPL:    INPUT
Stack:  Drops left side reference to string
Errors: ER_RT_FC - file not open
        ER_RT_NF - field not found
        ER_RT_RB - record too big
Calls:  ED$EDIT

QCO_INPUT_STR is exactly  equivalent  to  QCO_EDIT  with  an  initial  null
string.



        _____________
17.7.6  QCO_PRINT_INT

Prints an integer to the screen.

OP:     $6F
OPL:    PRINT
Stack:  Drops the integer
Calls:  UT$DISP
Bugs:   If the number $FFFF is assigned to an integer and then it is
        printed it will be represented as -1.

Before execution of this  operator  RTB_CRFL  is  tested  and,  if  set,  a
carriage return is sent to the screen and the flag cleared.



        _____________
17.7.7  QCO_PRINT_NUM

Prints a floating point number to the screen.

OP:     $70
OPL:    PRINT
Stack:  Drops the floating point number
Calls:  UT$DISP

Before execution of this  operator  RTB_CRFL  is  tested  and,  if  set,  a
carriage  return is sent to the screen and the flag cleared.  The format in
which a number is displayed is integer, decimal or scientific in that order
of precedence.



        _____________
17.7.8  QCO_PRINT_STR

Print a string to the screen.

OP:     $71
OPL:    PRINT
Stack:  Drops the string
Calls:  UT$DISP

Before execution of this  operator  RTB_CRFL  is  tested  and,  if  set,  a
carriage return is sent to the screen and the flag cleared.



        ____________
17.7.9  QCO_PRINT_SP

Prints a space to the screen.

OP:     $72
OPL:    PRINT
Stack:  No effect
Calls:  UT$DISP

This operator is  generated  by  use  of  the  ','  separator  in  a  PRINT
statement.

Before execution of this  operator  RTB_CRFL  is  tested  and,  if  set,  a
carriage return is sent to the screen and the flag cleared.



         ____________
17.7.10  QCO_PRINT_CR

Print a carriage return to the screen.

OP:     $73
OPL:    PRINT
Stack:  No effect
Calls:  UT$DISP

If a PRINT, INPUT or EDIT statement is not followed by a ';'  or  ','  then
this  operator  is automatically inserted.  It is not acted on immediately;
it sets the flag RTB_CRFL.

Before execution of this  operator  RTB_CRFL  is  tested  and,  if  set,  a
carriage return is sent to the screen and the flag cleared.

Note that if a carriage return results in scrolling the screen there is  an
automatic  delay;  the length of this delay is defined by DPW_DELY which is
in 50 millisecond units, the default being 10.



         ______________
17.7.11  QCO_LPRINT_INT

Sends an integer to the RS232.

OP:     $74
OPL:    LPRINT
Errors: ER_DV_NP - device missing
        ER_DV_CS - device load error

Exactly as PRINT_INT, except the CR flag is not tested.



         ______________
17.7.12  QCO_LPRINT_NUM

Send a floating point number to the RS232.

OP:     $75
OPL:    LPRINT
Errors: ER_DV_NP - device missing
        ER_DV_CS - device load error

Exactly as PRINT_NUM, except the CR flag is not tested.



         ______________
17.7.13  QCO_LPRINT_STR

Send a string to the RS232.

OP:     $76
OPL:    LPRINT
Errors: ER_DV_NP - device missing
        ER_DV_CS - device load error

Exactly as PRINT_STR, except the CR flag is not tested.



         _____________
17.7.14  QCO_LPRINT_SP

Send a space character to the RS232.

OP:     $77
OPL:    LPRINT
Errors: ER_DV_NP - device missing
        ER_DV_CS - device load error

Exactly as PRINT_SP, except the CR flag is not tested.



         _____________
17.7.15  QCO_LPRINT_CR

Send a carriage return to the RS232.

OP:     $78
OPL:    LPRINT
Errors: ER_DV_NP - device missing
        ER_DV_CS - device load error

As PRINT_CR except it is acted on immediately.



         __________
17.7.16  QCO_RETURN

Return from a procedure.

OP:     $79
OPL:    RETURN
Stack:  Unwinds the procedure

This operator follows the operator which stacks the return value.

All procedures return a value.  If no explicit value is  returned  then  it
will  return  integer  zero for integer procedures, floating point zero for
floating point procedures or a null string for string procedures.

See EXAMPLE 5.



         _________________
17.7.17  QCO_RETURN_NOUGHT

For an integer procedure this is the default return.

OP:     $7A
OPL:    RETURN
Stack:  Stack the integer zero and then unwind the procedure

Stacks default return value, then exactly the same as QCO_RETURN.



         _______________
17.7.18  QCO_RETURN_ZERO

For an floating point procedure this is the default return.

OP:     $7B
OPL:    RETURN
Stack:  Stack a floating point zero and then unwind the procedure

Stacks default return value, then exactly the same as QCO_RETURN.



         _______________
17.7.19  QCO_RETURN_NULL

For a string procedure this is the default return.

OP:     $7C
OPL:    RETURN
Stack:  Adds a null string and the unwinds the procedure

Stacks default return value,  on  the  stack,  then  exactly  the  same  as
QCO_RETURN.



         ________
17.7.20  QCO_PROC

Call a procedure.

OP:     $7D
OPL:    procnam:
Stack:  Initialises procedure
Errors: ER_RT_PN - procedure not found
        ER_RT_NP - wrong number of parameters
        ER_RT_UE - undefined external
        ER_EX_TV - parameter type mis-match
        ER_AL_NR - out of memory
        ER_GN_BL - test explicitly for low battery error
Calls:  PK$RBYT, PK$RWRD, PK$READ, DV$LKUP, DV$VECT


First checks to see if a language extension of that name  has  been  booted
into  memory  (see section 11.1.4.3).  If not it searches the 4 devices for
an OPL procedure of the right name.  It starts with the default device.  So
if the procedure called was on C:  then it searches in the order C:, D:, A:
and B:.

If a language extension has been found (for example LINPUT)  it  calls  the
relevant  vector  and  the  device  is  then  responsible  for checking the
parameters and handling the stack.  See section 17.12.2.

If it is an OPL procedure the header information is read in and the  memory
required  checked.  The external references are then checked and the fixups
on the strings and arrays performed.  See EXAMPLE 4.

The Q code is then read in, and RTA_PC and RTA_SP  are  set  to  their  new
values.



         _____________
17.7.21  QCO_BRA_FALSE

Branches if the integer on the stack is false.

OP:     $7E
OPL:    UNTIL, WHILE, IF, ELSEIF
Stack:  Drop the offset

Adds the integer following the operator to RTA_PC if the value on the stack
is zero.



         ___________
17.7.22  QCO_ASS_INT

Assign an integer to a variable.

OP:     $7F
OPL:    =
Stack:  Drops the integer and the integer reference
Errors: ER_RT_RB - field too big
        ER_RT_FC - file not open
        ER_RT_NF - field not found
        ER_RT_RB - record too big

At the start of the operand the stack looks like:

High memory             Address of integer variable
                        0 (field flag)
Low memory              Integer
                or:
High memory             Field name
                        Logical file name (0,1,2 or 4)
                        1 (field flag)
Low memory              Integer

If the assign is to a field, it checks that the file is  open,  checks  the
field name and saves the value.

If not a field it simply saves the integer to the address.

See EXAMPLE 4.



         ___________
17.7.23  QCO_ASS_NUM

Assigns a floating point number.

OP:     $80
OPL:    =
Stack:  Drops the floating point number and the floating point reference
Errors: ER_RT_RB - field too big
        ER_RT_FC - file not open
        ER_RT_NF - field not found
        ER_RT_RB - record too big

Exactly the same as QCO_ASS_INT except it handles floating  point  numbers.
See EXAMPLE 4.



         ___________
17.7.24  QCO_ASS_STR

Assigns a string.

OP:     $81
OPL:    =
Stack:  Drops the string and the string reference
Errors: ER_RT_RT - field too big
        ER_LX_ST - string too long

Exactly the same as QCO_ASS_INT except it handles strings.  See EXAMPLE 4.



         _____________
17.7.25  QCO_DROP_BYTE

Drops a byte off stack.

OP:     $82
OPL:    -
Stack:  Drops byte



         _____________
17.7.26  QCO_DROP_WORD

Drops a word off the stack.

OP:     $83
OPL:    -
Stack:  Drops word

Used internally to drop unwanted results  off  the  stack,  for  example  a
statement "GET" which translates into RTF_GET,QCO_DROP_WORD.



         ____________
17.7.27  QCO_DROP_NUM

Drops a floating point number off the stack.

OP:     $84
OPL:    -
Stack:  Drops a floating point number

Used internally to OPL  when,  for  example,  a  floating  point  procedure
returns a value that is not required.



         ____________
17.7.28  QCO_DROP_STR

Drops a string off the stack.

OP:     $85
OPL:    -
Stack:  Drops a string off the stack

Used internally to OPL when, for example,  a  string  procedure  returns  a
string that is not required.



         ______________
17.7.29  QCO_INT_TO_NUM

Converts an integer into a floating point number.

OP:     $86
OPL:    -
Stack:  Drops an integer, stacks a float
Calls:  MT$BTOF
Bugs:   Integers are always taken as signed. To make unsigned:
                A=I% :IF I%<0 :A=A+65536 :ENDIF

Used for automatic type conversion.



         ______________
17.7.30  QCO_NUM_TO_INT

Converts a floating point number to integer.

OP:     $87
OPL:    -
Stack:  Drops float, stacks integer
Errors: ER_RT_IO - integer overflow
Calls:  IM$DINT, IM$FLOI
Bugs:   Always rounds down, 3.9 becomes 3 and -3.9 becomes -4.

Used for automatic type conversion.



         ______________
17.7.31  QCO_END_FIELDS

Indicates where the field names end.

OP:     $88
OPL:    OPEN, CREATE
Stack:  No effect

Only used internally at the end of an OPEN or CREATE command.  See  EXAMPLE
2.



         _____________
17.7.32  QCO_RUN_ASSEM

Runs machine code immediately after operator.

OP:     $89
OPL:    -
Stack:  No effect

Runs the code immediately after the operator as machine code.  On return if
there  are  no  errors  carry  must be clear and the B register must be the
number of bytes for RTA_PC to jump.  If there is an error carry must be set
and the B register should contain the number of the error to be reported.

This cannot be generated from the editor.



      _______ _________
17.8  INTEGER FUNCTIONS


These functions return integer values.



        ________
17.8.1  RTF_ADDR

Returns the address of a numeric variable.

OP:     $8A
OPL:    ADDR
Stack:  Drops the 'left side' reference, stacks the address.
Bugs:   Cannot deal with elements of arrays, though they may be easily
         calculated.

In the case of arrays ADDR returns the address of the first  element  which
is immediately after the word giving the size of the array.

So "PRINT PEEKW(ADDR(A%))" is exactly the same as "PRINT A%" and
"PRINT PEEKW(ADDR(A%())) is the same as "PRINT A%(1)".



        _______
17.8.2  RTF_ASC

Returns the ASCII value of the first character of the string.

OP:     $8B
OPL:    ASC
Stack:  Drops the string, stacks an integer
Bugs:   If the string is zero length it returns zero.



        _______
17.8.3  RTF_DAY

Returns the current day of the month - in the range 1 to 31.

OP:     $8C
OPL:    DAY
Stack:  Stack an integer



        ________
17.8.4  RTF_DISP

Displays a string, a record or the last string displayed, using cursor keys
for viewing and waiting for any other key to exit.

OP:     $8D
OPL:    DISP
Para1:  Integer: 1 - displays para2
                 0 - redisplays the last DISPed string (ignores para2)
                -1 - displays the current record (ignores para2)
Para2:  String to be displayed
Stack:  Drops the two parameters, stacks the exit key as an integer.
Calls:  UT$DISP
Bugs:   In the case para1 is zero it displays the contents of RTT_BUF.
        RTT_BUF is used by a number of other operand/operators, for
        instance by string adds.

The display used is the same as that used by FIND in the top  level.   Each
field,  delimited  by a TAB character, is on a different line.  There is no
limit to the number of fields.



        _______
17.8.5  RTF_ERR

Returns the current error value.

OP:     $8E
OPL:    ERR
Stack:  Stack the error number as an integer

When the language starts running the value of  RTB_EROR  is  zero.   If  an
error is encountered and handled by a TRAP or ONERR the value remains until
the next error or a TRAP command.



        ________
17.8.6  RTF_FIND

Finds a string in the current file.

OP:     $8F
OPL:    FIND
Stack:  Drops the search string, stacks the record number.
Bugs:   FIND does not do an automatic NEXT, the correct loop structure is:

                DO
                 IF FIND "ABC"
                  statement(s)
                 ENDIF
                 NEXT
                UNTIL EOF

If no record is found zero is returned and the current record  remains  the
same as before the FIND.



        ________
17.8.7  RTF_FREE

Returns the amount of free memory.

OP:     $90
OPL:    FREE
Stack:  Stack the resulting integer.

Calculates the amount of free memory by subtracting  ALA_FREE  from  RTA_SP
and then subtracting $100.



        _______
17.8.8  RTF_GET

Get a single character.

OP:     $91
OPL:    GET
Stack:  Stack the character as an integer.
Calls:  KB$GETK
Bugs:   The ON/CLEAR key returns 1.  It can be difficult to break out
        of a tight loop with a GET using the ON/CLEAR, Q keys.  With
        perseverance it is normally possible.

If there is a key in the buffer it gets that  key  first.   If  no  key  is
received the Organiser will turn itself off after the timeout.  See section
7.4.1 and section 7.4.4.



        ________
17.8.9  RTF_HOUR

Returns the current hour of the day - in the range 0 to 23.

OP:     $92
OPL:    HOUR
Stack:  Stack the number as an integer.



         ________
17.8.10  RTF_IABS

Does an ABS on an integer.

OP:     $93
OPL:    IABS
Stack:  Leaves the integer on the stack.

Converts a negative integer to a positive integer.  If ABS is used in place
of  IABS  the  result  would be the same but the function would require two
unnecessary type conversions.  IABS is significantly faster than ABS.



         _______
17.8.11  RTF_INT

Converts a floating point number to an integer.

OP:     $94
OPL:    INT
Stack:  Drops float, stacks integer
Errors: ER_RT_IO - integer overflow
Calls:  IM$DINT, IM$FLOI
Bugs:   Always rounds down, INT(3.9) is 3 and INT(-3.9) is -4.

Identical to QCO_NUM_TO_INT.



         _______
17.8.12  RTF_KEY

Returns any key in the input buffer.  Zero if no key is waiting.

OP:     $95
OPL:    KEY
Stack:  Stack the integer
Bugs:   Except after an "ESCAPE OFF" statement, KEY cannot pick up the
        ON/CLEAR key.



         _______
17.8.13  RTF_LEN

Returns the length of the string.

OP:     $96
OPL:    LEN
Stack:  Drops string, stacks the length as an integer



         _______
17.8.14  RTF_LOC

Locates one string in another, returns zero if not found.

OP:     $97
OPL:    LOC
Para1:  String to be searched
Para2:  String to locate
Stack:  Drops the two strings, stacks the resulting position as an integer



         ________
17.8.15  RTF_MENU

Gives a menu of options.

OP:     $98
OPL:    MENU
Stack:  Drops the string, stacks the exit item as an integer
Calls:  MN_AXDP
Errors: ER_RT_MU - menu error
        ER_FN_BA - bad argument
Bugs:   In the input string the menu items are delimited by commas.
        Before MN_AXDP is called the string is converted to individual
        strings each terminated by a null word.  It is possible to
        have too many items.
        Don't have spaces or tabs as part of menu items, they can have
        unpredictable effects.

The normal input is a string with each menu item delimited by a comma.   An
item  is selected either by a unique first letter or by positioning on that
item and pressing the EXE key.  If the menu exits by the  ON/CLEAR  key  it
returns zero.



         __________
17.8.16  RTF_MINUTE

Returns the current minute of the hour - in the range 0 to 59.

OP:     $99
OPL:    MINUTE
Stack:  Stack the number as an integer.



         _________
17.8.17  RTF_MONTH

Returns the current month of the year - in the range 0 to 11.

OP:     $9A
OPL:    MONTH
Stack:  Stack the number as an integer.



         _________
17.8.18  RTF_PEEKB

Peeks a byte at the given address.

OP:     $9B
OPL:    PEEKB
Stack:  Drops the address, stacks the result as an integer

If the address is in the ranges $00-$3F and $282-$400 then it returns zero.
These  ranges  are  the  processor  registers and the custom chip's control
addresses.  See section 9.3.2 for more  details.   The  informed  user  may
access these addresses via machine code.



         _________
17.8.19  RTF_PEEKW

Peeks a word at the given address.

OP:     $9C
OPL:    PEEKW
Stack:  Drops the address, stacks the result as an integer

See the comments after RTF_PEEKB.



         ___________
17.8.20  RTF_RECSIZE

Returns the size of the current record.

OP:     $9D
OPL:    RECSIZE
Stack:  Stack the size as an integer.
Bugs:   The maximum size of a record is 254, this includes the field
         separators.

See 17.2.10 for more details.



         __________
17.8.21  RTF_SECOND

Returns the current second of the minute - in the range 0 to 59.

OP:     $9E
OPL:    SECOND
Stack:  Stack the number as an integer.



         ________
17.8.22  RTF_IUSR

Calls machine code.

OP:     $9F
OPL:    USR
Para1:  Address of the machine code
Para2:  The value to be passed in the D register
Stack:  Drops the parameters, stacks the X register on return



         _________
17.8.23  RTF_SADDR

Returns the address of a string.

OP:     $C9
OPL:    ADDR
Stack:  Stack the result

Returns the address of the length byte, the  byte  after  the  maximum
length.

In the case of an array it returns the address of the length  byte  of  the
first  element  of the array.  So "ADDR(A$())-2" is the address of the size
the array (a word) and "ADDR(A$())-3" is the address of the maximum  string
length (a byte).



         ________
17.8.24  RTF_VIEW

View a string, or the last string viewed.

OP:     $A0
OPL:    VIEW
Para1:  Line on which to view (1 or 2)
Para2:  String to be viewed
Stack:  Drops the parameters, stacks the exit character as an integer

If the string is null it re-displays the last string VIEWed (which is  held
in RTT_BUF).



         ________
17.8.25  RTF_YEAR

Returns the current year - in the range 0 to 99.

OP:     $A1
OPL:    YEAR
Stack:  Stack the number as an integer



         _________
17.8.26  RTF_COUNT

Returns the number of records in the current file.

OP:     $A2
OPL:    COUNT
Stack:  Stack the result as an integer
Calls:  FL$SIZE



         _______
17.8.27  RTF_EOF

Returns TRUE if the position in the file is at the end  of  file.   If  the
current record is the last record of the file, EOF returns FALSE.

OP:     $A3
OPL:    EOF
Stack:  Stack result as an integer
Errors: ER_RT_FC - file not open
Bugs:   If there are no records this returns true.

Returns TRUE if the current record buffer is  zero.   When  OPL  appends  a
record  with  zero  length  it  adds a TAB ($09) character so that it never
actually saves a null string.



         _________
17.8.28  RTF_EXIST

Returns TRUE is the file exists.

OP:     $A4
OPL:    EXIST
Stack:  Drops string, stacks result
Calls:  FL$OPEN



         _______
17.8.29  RTF_POS

Returns the current record number in the current file.

OP:     $A5
OPL:    POS
Stack:  Stack the result
Calls:  FL$SETP, FL$RECT, FL$RSET
Errors: ER_RT_FC - file not open
Bugs:   If no records still return 1.



      ________ _____ _________
17.9  FLOATING POINT FUNCTIONS



These functions return a floating point value.



        _______
17.9.1  RTF_ABS

Does an ABS on a floating point number.

OP:     $A6
OPL:    ABS
Stack:  Leaves the floating point number on the stack.
Calls:  FN_ABS



        ________
17.9.2  RTF_ATAN

Returns the arctangent of the input in radians.

OP:     $A7
OPL:    ATAN
Stack:  Drops the input floating point number, stacks the result
Calls:  FN_ATAN
Bugs:   Returns values in the range plus or minus pi/2



        _______
17.9.3  RTF_COS

Returns the cosine of the input, the input being in radians.

OP:     $A8
OPL:    COS
Stack:  Drops the input floating point number, stacks the result
Calls:  FN_COS
Errors: ER_FN_BA - bad argument if the absolute value is greater than
                        3141590.



        _______
17.9.4  RTF_DEG

Converts the input from radians to degrees.

OP:     $A9
OPL:    DEG
Stack:  Drops the input floating point number, stacks the result
Calls:  FN_DEG
Bugs:   All this does is multiply the input by 57.29...



        _______
17.9.5  RTF_EXP

Returns the value of e raise to the specified power.

OP:     $AA
OPL:    EXP
Stack:  Drops the input floating point number, stacks the result
Calls:  FN_EXP
Errors: ER_FN_BA - bad argument if the absolute value is greater than 229.



        _______
17.9.6  RTF_FLT

Converts an integer to floating point format.

OP:     $AB
OPL:    FLT
Stack:  Drops the input integer, stacks the result
Calls:  MT$BTOF
Bugs:   Integers are always taken as signed. To make unsigned:

                A=I% :IF I%<0 :A=A+65536 :ENDIF

Exactly the same effect as QCO_INT_TO_NUM.



        ________
17.9.7  RTF_INTF

Rounds a floating point number down to a whole number.

OP:     $AC
OPL:    INTF
Stack:  Drops the input floating point number, stacks the result
Calls:  IM$DINT, IM$FLOI

Essential to use INTF rather than INT if the number is out of  the  integer
range.



        ______
17.9.8  RTF_LN

Returns the natural logarithm of the input.

OP:     $AD
OPL:    LN
Stack:  Drops the input floating point number, stacks the result
Errors: ER_FN_BA - bad argument
Calls:  FN_LN
Bugs:   The input must be greater than 0.



        _______
17.9.9  RTF_LOG

Returns the base 10 logarithm of the input.

OP:     $AE
OPL:    LOG
Stack:  Drops the input floating point number, stacks the result
Errors: ER_FN_BA - bad argument
Calls:  FN_LOG
Bugs:   The input must be greater than 0.




         ______
17.9.10  RTF_PI

Returns the number pi = 3.14159265359.

OP:     $AF
OPL:    PI
Stack:  Stack the result
Calls:  FN_PI



         _______
17.9.11  RTF_RAD

Converts the input number to radians.  The inverse of DEG.

OP:     $B0
OPL:    RAD
Stack:  Drops the input floating point number, stacks the result
Calls:  FN_RAD
Bugs:   All this does is divide the input by 57.29...



         _______
17.9.12  RTF_RND

Returns a pseudo-random number in the range 0(inclusive) to 1(exclusive).

OP:     $B1
OPL:    RND
Stack:  Stack the result
Calls:  FN_RND



         _______
17.9.13  RTF_SIN

Returns the sine of the input, the input being in radians.

OP:     $B2
OPL:    SIN
Stack:  Drops the input floating point number, stacks the result
Calls:  FN_SIN
Errors: ER_FN_BA - bad argument if the absolute value is greater than
                        3141590.



         _______
17.9.14  RTF_SQR

Returns the square root of the input.

OP:     $B3
OPL:    SQR
Stack:  Drops the input floating point number, stacks the result
Calls:  FN_SQRT
Errors: ER_FN_BA - bad argument if negative



         _______
17.9.15  RTF_TAN

Returns the tangent of the input, the input being in radians.

OP:     $B4
OPL:    TAN
Stack:  Drops the input floating point number, stacks the result
Calls:  FN_TAN
Bugs:   At the discontinuities in TAN, pi/2, 3*pi/2, etc, the values
        returned are either greater than 1E10 or less than -1E10.



         _______
17.9.16  RTF_VAL

Returns the input string as a number.

OP:     $B5
OPL:    VAL
Stack:  Drops the input string, stacks the result
Errors: ER_MT_FL - conversion to number failed
Calls:  MT_BTOF
Bugs:   This routine insists that the whole string is used in the
        conversion, so VAL("12.34 ") generates an error.  The null string
        also gives an error.



         _________
17.9.17  RTF_SPACE

Returns the amount of space on the current device.

OP:     $B6
OPL:    SPACE
Stack:  Stack the result as floating point number
Calls:  FL$SIZE
Errors: ER_RT_FC - file not open
Bugs:   This may be longer than a word!



       ______ _________
17.10  STRING FUNCTIONS



         _______
17.10.1  RTF_DIR

Returns the name of the first/next file on a device.

OP:     $B7
OPL:    DIR$
Stack:  Drops the input string, stack the resulting string
Calls:  FL$CATL
Errors: ER_FN_BA - bad argument

If the string is non-null it checks that it is of the form "A:" or "A".  It
splits  out the device name and returns the first file name preceded by the
device name.  If the string is null it returns the next file name,  on  the
device  already  specified.   When there are no more file it returns a null
string.



         _______
17.10.2  RTF_CHR

Converts the integer input to a one character string.

OP:     $B8
OPL:    CHR$
Stack:  Drops the input integer, stacks the resulting string
Errors: ER_FN_BA - bad argument if out of the range 0-255



         _________
17.10.3  RTF_DATIM

Returns the date-time string in the form:

        "TUE 04 NOV 1986 10:44:29"

OP:     $B9
OPL:    DATIM$

Stack:  Stacks the resulting string



         ________
17.10.4  RTF_SERR

Returns the error string associated with the integer error number.

OP:     $BA
OPL:    ERR$
Stack:  Drops the input integer, stacks the resulting string
Errors: ER_FN_BA - bad argument (if not a byte)
Calls:  ER$LKUP
Bugs:   Returns "*** ERROR ***" if less than the lowest recognised
        error number.



         _______
17.10.5  RTF_FIX

Returns the floating point number as  a  string  with  a  fixed  number  of
decimal places.

OP:     $BB
OPL:    FIX$
Para1:  The floating point number
Para2:  The require number of decimal places
Para3:  The field size
Stack:  Drops input parameters, stacks the resulting string
Calls:  MT_FBDC
Bugs:   If the number does not fit, '*'s are inserted



         _______
17.10.6  RTF_GEN

Returns the floating point number as a string.  This is the same format  as
used by QCO_PRINT_NUM.

OP:     $BC
OPL:    GEN$
Stack:  Drops the floating point number
Calls:  MT_FBGN
Bugs:   If the number does not fit, '*'s are inserted

The format in  which  the  number  is  displayed  is  integer,  decimal  or
scientific in that order of precedence.



         ________
17.10.7  RTF_SGET

Get a character and return it as a one character string.

OP:     $BD
OPL:    GET$
Stack:  Stack the resulting string
Calls:  KB$GETK
Bugs:   The ON/CLEAR key returns a valid string.  It can be difficult to
        break out of a tight loop with a GET$ using ON/CLEAR, Q keys.
        With perseverance it is normally possible.



         _______
17.10.8  RTF_HEX

Converts the integer into a hexadecimal string.

OP:     $BE
OPL:    HEX$
Stack:  Drops input integer, stacks resulting string
Calls:  UT_XTOB
Bugs:   Input must be in the integer range.



         ________
17.10.9  RTF_SKEY

Returns any keys in the input buffer as a string.  Returns the null  string
if no key is waiting.

OP:     $BF
OPL:    KEY$
Stack:  Stack the string
Calls:  KB$TEST, KB$GETK
Bugs:   Except after an "ESCAPE OFF" statement, KEY cannot pick up the
        ON/CLEAR key.  ON/CLEAR key normally suspends OPL execution.



          ________
17.10.10  RTF_LEFT

Returns the first n characters of the string.

OP:     $C0
OPL:    LEFT$
Para1:  The string
Para2:  Number of characters to keep
Stack:  Drops the input parameters, stacks the resulting string
Bugs:   If the string is shorter than the number of characters the entire
        string is returned.



          _________
17.10.11  RTF_LOWER

Converts the string to lower case.

OP:     $C1
OPL:    LOWER$
Stack:  Drops the input string, stacks the result



          _______
17.10.12  RTF_MID

Returns the middle of a string.

OP:     $C2
OPL:    MID$
Para1:  The string
Para2:  The start character
Para3:  The number of characters to be kept
Stack:  Drops the input parameters, stacks the resulting string
Bugs:   If there are insufficient characters the rest of the string is
        returned.

You can get all the characters after the nth by the statement:

                MID$(a$,n,255)



          _______
17.10.13  RTF_NUM

Converts a number to an integer string.

OP:     $C3
OPL:    NUM$
Para1:  The floating point number
Para2:  The maximum size of the string
Stack:  Drops the input parameters, stacks the resulting string.
Calls:  MT_FBIN
Bugs:   If the number does not fit, '*'s are inserted
        The number does not have to be in usual integer range.



          _________
17.10.14  RTF_RIGHT

Returns the last n characters of a string.

OP:     $C4
OPL:    RIGHT$
Para1:  The string
Para2:  The number of characters wanted
Stack:  Drops the input parameters, stacks the resulting string
Bugs:   If the string is shorter than the number of characters the entire
        string is returned.



          ________
17.10.15  RTF_REPT

Repeats the string n times.

OP:     $C5
OPL:    REPT$
Para1:  The string
Para2:  The repeat count
Stack:  Drops the integer and input string, stacks the result
Bugs:   If the repeat count is zero no error is given.
Errors: ER_MT_FN - function argument error
        ER_LX_ST - string too long



          _______
17.10.16  RTF_SCI

Returns the floating point number as a string in scientific form.

OP:     $C6
OPL:    SCI$
Para1:  The floating point number
Para2:  Number of decimal places required
Para3:  Field width
Stack:  Drops the floating point number, stacks the result
Calls:  MT_FBEX
Bugs:   If the number does not fit, '*'s are inserted



          _________
17.10.17  RTF_UPPER

Converts the string to upper case.

OP:     $C7
OPL:    UPPER$
Stack:  Drops the input string, stacks the result



          ________
17.10.18  RTF_SUSR

Calls machine code.

OP:     $C8
OPL:    USR$
Para1:  Address of the machine code
Para2:  The value to be passed in the D register
Stack:  Drops the parameters, stacks the string pointed at by the
         X register



       _____
17.11  FILES


         ________
17.11.1  CREATING



Before a file is created a check is made  that  no  file  exists  with  the
specified  name on that device.  The first unused record number over $90 is
assigned to the file and the file name record is  written  to  the  device.
The process then continues in the same way as opening a file.

The file name records are type $81.  The file name record for a file called
"AMANDA", with record file type $95 looks like:

                09 81 41 4D 41 4E 44 41 20 20 20 95



         _______
17.11.2  OPENING



First the file name record is located to ensure that the file exists.   The
file  record  type  and the device on which the file was found are saved in
the file block (RTT_FILE).  The field names  are  saved  in  the  allocator
field  name cell corresponding to the logical name and the file buffer cell
is expanded to 256 bytes.  The record position is initialised to 1 and  the
first record, if it exists, is read.

If the file has just been created or the record is empty the current record
will be null and the EOF flag is set.

See section 6.5.1.4.1 for the format of the file blocks.



         __________________
17.11.3  LOGICAL FILE NAMES



Up to 4 files may be open at one time; to distinguish between then  logical
file  names are used.  The 4 logical file names:  A,B,C, and D, are used to
determine which file is to be operated on by the file commands.

This means that you can open files in any order but have a constant way  of
referring  to them.  The USE operator selects which file is affected by the
following commands:

APPEND          BACK            CLOSE           ERASE
FIRST           NEXT            LAST            POSITION
UPDATE

and the following functions:

COUNT           DISP            EOF             FIND
POS             RECSIZE         SPACE



         ___________
17.11.4  USING FILES



There is no functional difference between the logical file names.

When opening a file the file name record and the first record are  located;
two  cells,  one a buffer and one for the field names are grown.  Closing a
file entails the two cells being shrunk.

All references to fields must include the logical file name.   This  serves
two  purposes;  it  allows statements such as "A.MAX=B.VALUE" and it allows
the language to distinguish between ordinary variables and field names.



       _______________
17.12  PROCEDURE CALLS


To write  compact,  fast  code  it  is  important  to  understand  the  way
procedures are loaded and automatically overlaid.

A procedure call consists  of  a  procedure  name  followed  by  up  to  16
parameters.  The procedure name may include an optional '$' or '%' but must
terminate with a ':'.  If parameters are supplied they must be separated by
commas and be enclosed in brackets.

There are two main types of procedure.  In standard OPL  procedures  the  Q
code is loaded onto the stack and then executed.  The second type are known
as a device  procedure  or  language  extensions;  they  are  identical  to
standard  procedures in appearance, but differs in that it is recognised by
the device lookup and runs as self-contained machine code.



         ___________________
17.12.1  STANDARD PROCEDURES


When a QCO_PROC operator is encountered the parameters will already  be  on
the  stack,  along with the parameter count and the parameter types.  After
the operator is the name of the procedure.

The following list of actions are then carried out:

     1.  Check if it is a language extension/device call
     2.  Search for the procedure starting with the default device
     3.  Check that there is sufficient memory
     4.  Set new RTA_SP, RTA_FP
     5.  Check the parameter count
     6.  Check the parameter types
     7.  Set up a table of variables declared GLOBAL
     8.  Set up the parameter table
     9.  Resolve the externals, build an externals table
    10.  Zero all variable space
    11.  Fix-up strings
    12.  Fix-up arrays
    13.  Load the code
    14.  Set new RTA_PC


The code is loaded every time a  procedure  is  called.   This  means  that
recursive  procedures  are allowed but that the stack will grow by the size
of the Q code + data space + overhead for each call.  On an XP, following a
Reset, the procedure:

                RECURS:(I%)
                IF I%
                 RECURS:(I%-1)
                ENDIF

allows values up to 315 before an 'OUT OF MEMORY' error is given.

See EXAMPLE 3.



         ___________________
17.12.2  LANGUAGE EXTENSIONS


Language extension are also referred to as device procedures.  Examples are
LINPUT, LSET and LTRIG in the RS232 interface.

To test if a procedure is a language extension, call DV$LKUP.   This  looks
through  the  devices loaded in order of priority.  If a language extension
is found it returns with carry clear, the device number in the  A  register
and  the vector number in the B register, suitable for an immediate call to
DV$VECT to run the code.

The machine code should check that any parameters that have been passed are
correct, do whatever it has to do, add the return variable to the stack and
return.  It is essential  to  return  the  right  variable  type.   If  the
extension name terminates with a '$' it must return a string, if with a '%'
it requires an integer, otherwise an 8 byte floating point number.

Note that a variable number of parameters can be passed to a device.

As a simple example, consider a language  extension  to  add  two  integers
without  giving  an  error  if the sum overflows.  If only one parameter is
given the value is simply incremented, again without giving an error.   The
assembler for this extension called "ADD%" is:

XADD:
        LDX     RTA_SP:
        LDA     A,0,X
        BEQ     1$                      ; wrong number of parameters
        DEC     A
        BEQ     INCREM                  ; increment 1 parameter
        DEC     A
        BEQ     XXADD                   ; add the two
1$:
        LDA     B,#ER_RT_NP             ; wrong number of parameters
        SEC                             ; bad return
        RTS
INCREM:
        LDA     A,1,X                   ; load parameter type
        BNE     WRGTYP                  ; branch if not integer
        LDD     2,X
        ADDD    #1
EXIT:
        DEX
        DEX
        STX     RTA_SP:
        STD     0,X                     ; save return value
        CLC                             ; good return
        RTS
XXADD:
        LDA     A,1,X
        BNE     WRGTYP                  ; branch if not integer
        LDA     A,4,X
        BNE     WRGTYP                  ; branch if not integer
        LDD     2,X                     ; and add the two integers
        ADDD    5,X
        BRA     EXIT
WRGTYP:
        lda     b,#ER_FN_BA             ; report wrong parameters type
        SEC                             ; bad return
        RTS

See chapter 11 for the necessary pack header.



       ___________
17.13  WRITING OPL


Like any programming language there is an infinite number of approaches  to
every problem.  The aim should be to produce fast, compact Q code that runs
in a minimum of memory but is also easy to  write  and  understand.   These
aims  inevitably  conflict with each other; the correct balance varies from
application to application.

For example, the decision to use a separate procedure, rather than  writing
the code in line, is a matter of considering the difference in Q code size,
the extra stack required at run time, the time overhead  required  to  load
and return from a procedure and finally style.

It is impossible to give definitive rules on writing code but it  is  worth
taking the following points into account.



         ______________
17.13.1  COMPACT Q CODE


     1.  Only use procedures where appropriate
     2.  If it makes no difference, use LOCALs instead of GLOBALs
     3.  Use short field names
     4.  Use short global names
     5.  If you repeatedly use a CHR$ with the same value, assign it  to  a
         variable
     6.  Use "RETURN" instead of "RETURN 0" or "RETURN """
     7.  Use hexadecimal integers instead of negative integers



         ___________________
17.13.2  COMPACT ON RUN TIME


     1.  Write short Q code (as above)
     2.  Use a small main procedure to call several small procedures.
     3.  Use integers instead of floating point numbers
     4.  Use short field names
     5.  Use short global names
     6.  Check the deepest part of the code by adding,  temporarily,  PRINT
         FREE :GET.  Then consider restructuring the procedures to decrease
         the amount of stack used.



         _________
17.13.3  FAST CODE


Each operand/operator has an  overhead  of  .05  ms.   Most  integer  based
operands/operators are very fast and run in less than .1 ms.

The following timings are rough and should only be used as a guide:

        _______                      ____ ____
        OPERAND                      Time (ms)
        RND                             10
        AT                              .15
        PRINT a string                  .5
        INT_TO_NUM                      2.5
        NUM_TO_INT                      2
        SIN/COS                         150
        TAN                             350
        ATAN                            170
        SQR                             240
        EXP                             130
        LOG/LN                          200
        Integer add/subtract            .1
        Integer multiply/divide         1
        Floating point add/subtract     3
        Floating point multiply         10
        Floating point divide           20
        Accessing a field               5

PRINT_CR has a default delay  of  500  milliseconds.   This  value  can  be
altered by poking the value in DPW_DELY.

     1.  don't use too many procedures, regard  them  as  being  similar  to
         overlays
     2.  place the procedures at the beginning of the pack, with  the  most
         frequently used at the start
     3.  Use LOCALs or GLOBALs rather than field variables
     4.  Don't use procedures inside time critical loops,  write  the  code
         in-line
     5.  Use integers instead of floating point numbers
     6.  Write short Q code (less code to load)
     7.  Use LOCALs instead of GLOBALs



           __________
17.13.3.1  PROCEDURES


The smallest time overhead on loading, and returning form a procedure is  8
ms.   This  overhead  increases  if  the  procedure follows other blocks or
records on the device.  It also increases if the procedure is  not  on  the
same  device  as  the  top  level procedure (as it will have to search that
device first).  See chapter 12  for  a  full  explanation  of  the  storage
mechanism.



           _____
17.13.3.2  FILES


Some of the file operators have to count up the pack  each  time  they  are
used.   For  the  sake  of speed NEXT remembers its position on each of the
packs.  However it only remembers one position on each pack so:

                USE B
                NEXT
                A.MAX=B.VAL
                USE A
                APPEND

where file A is on B:  and file B on C:  is significantly  faster  than  if
they are both on the same device.

BACK however always has to count up the pack to locate a  record  and  this
can  take  a  noticeable  time.   Remember  that erased records, as well as
readable ones, will slow down the location of a record.



         __________
17.13.4  CODE STYLE


Before starting to write a program (which normally will consist of a number
of  procedures) first decide the relative importance of speed of execution,
compactness of the Q code and the amount of stack used.

Then rough out the procedure structure.  For example, in the  case  of  the
finance pack the main procedure is called FINS:

fins:
local i%,j%
do
  i%=menu("BANK,EXPENSES,NPV,IRR,COMPOUND,BOND,MORTGAGE,APR,END")
  if     i%=1 : bank:
  elseif i%=2 : expenses:
  elseif i%=3 : npv:
  elseif i%=4 : irr:
  elseif i%=5
    do
      j%=menu("VALUE,FUTURE,PAYMENT,DURATION,INTEREST,END")
      if     j%=1 : value:
      elseif j%=2 : future:
      elseif j%=3 : payment:
      elseif j%=4 : duration:
      elseif j%=5 : interest:
      endif
    until j%=0 or j%=6
  elseif i%=6 : bond:
  elseif i%=7 : mortgage:
  elseif i%=8 : apr:
  endif
until i%=0 or i%=9

Your style may vary if you are writing on the  emulator  or  the  ORGANISER
itself.   On  the  ORGANISER  it  is  worth, as a general rule, making only
limited use of the ':' option to have more than one statement  on  a  line.
On the emulator you may prefer to write multiple statements on a line.  The
procedure above was written using a full screen editor which  is  reflected
in the elegant use of non-functional spaces.

It is very helpful to indent the code by logical function.   This  is  very
useful in matching IF/ENDIF and loop commands.

Comment the code.  The logic may seem very obvious when you  write  it  but
other  people  may  want  to  read  it, or you may return to the code after
several months.  In most cases the extra space taken  by  the  comments  is
well  worth  it.   Remember  that comments make no difference to the Q code
size.

Use brackets if you are unsure  of  the  operator  precedence.   This  adds
nothing to the Q code size but makes your intentions absolutely clear.

When using the ':' separator it is not necessary to precede it by  a  space
when  the  preceding  characters  cannot  be  taken as a variable name.  So
"A%=1:B%=2" is valid but "A%=B%:B%=C%"  gives  a  syntax  error.   It  can,
however,  save  time  and make the code more readable if you always proceed
the ':' separator with a space.



       __________
17.14  TRANSLATOR


The translator scans the source code, statement by  statement,  translating
it  into Q code.  All expressions are converted to reverse polish (postfix)
form so that, at run time, the operators can be executed as  soon  as  they
are encountered.

It is beyond the scope of this document to describe the detailed working of
the  translator.  Fortunately, such a description is not necessary in order
to understand either the execution of the code or the writing of  efficient
code.



       _________________________
17.15  SYSTEM SERVICES INTERFACE



         _______
17.15.1  RM$RUNP

VECTOR NUMBER:          100
INPUT PARAMETERS:       X register - points at the name of the procedure
                        B register - if set then runs the calculator
OUTPUT VALUES:          None

DESCRIPTION

    Runs the language by  loading  and  running  the  OPL  procedure.   The
    procedure can not have any parameters.

EXAMPLE

For example, to run a procedure called BOOT:

                LDX     pname           ; address of the name of the
procedure
                LDA     B,#BLANTYP
                OS      FL$BOPN         ; test that procedure exists
                BCS     2$
                LDX     pname           ; address of the name of the
procedure
                CLR     B
                OS      RM$RUNP
                BCC     1$
        2$:
                OS      ER$MESS         ; report error
        1$:
                RTS

ERRORS:                 Any error is possible

BUGS

    If the procedure does not  exist  the  error  message  will  contain  a
    garbage name.

    Every time RM$RUNP is run the language re-initialises, it resets RTA_SP
    to BTA_SBAS, zeroes all the file cells and close all the files.



         _______
17.15.2  LN$STRT

VECTOR NUMBER:          079
INPUT PARAMETERS:       B register -
                                0 translating language procedures
                                1 translating CALC expressions
                                2 locating errors in CALC
                                3 locating errors in language procedures

                        X register - offset in Q code to run time error
                                ignored if B register 0 or 1.

OUTPUT VALUES:          translated result, if successful, in OCODCELL
                        If an error is detected:
                                X register - offset to error in TEXTCELL
                                B register - error number

DESCRIPTION

    Runs the translator.

EXAMPLE

                CLR     B               ; translate language procedure
                OS      LN$STRT
                BCC     1$
                OS      ER$MESS         ; report error
        1$:
                RTS

ERRORS:                 Many

BUGS

If the B register is 2 or 3 and the value of X is greater than  the  length
of  the  Q code, in other words you are asking for an error past the end of
the code, the effect is unpredictable.



       ______________________
17.16  MACHINE CODE INTERFACE


From the information in this chapter, the programmer  knows  exactly  where
everything is on the stack.

When variables are declared they are used in order, so:

                LOCAL A%,B%
                PRINT ADDR(A%)=ADDR(B%)+2
                GET

will print -1, i.e. TRUE.

See section 6.5.2.2 for details of where machine code  can  be  permanently
hidden.

For short machine code routines you can  use  this  crude,  but  effective,
procedure:

                LOADR:(ADDR%,CODE$)
                LOCAL A%,B1%,B2%,I%
                A%=ADDR%
                I%=1
                WHILE I%<LEN(CODE$)
                 B1%=ASC(MID$(CODE$,I%,1))-%0
                 IF B1%>9 :B1%=B1%-7 :ENDIF
                 B2%=ASC(MID$(CODE$,I%+1,1))-%0
                 IF B2%>9 :B2%=B2%-7 :ENDIF
                 POKEB A%,B1%*16+B2%
                 A%=A%+1
                 I%=I%+2
                ENDWH

When calling this procedure you must pass the machine code in digital  form
and  the  address  where to put the machine code.  It is essential that the
programmer ensures there is enough room for the machine code at the address
given.

A calling sequence might look like:

                MAIN:
                GLOBAL MC%,MC$(10)
                MINIT: :REM Initialise the machine code
                ..
                CELL%=USR(MC%,100) :REM GRABs a cell of size 100
                IF CELL%=0
                 PRINT "No cell free"
                 GET :RAISE 0
                ENDIF
                ..
                RETURN


                MINIT:
                A$="3F012403CE000039"
                IF LEN(A$)/2>LEN(MC$)
                  PRINT "Not enough room for MC"
                  GET :RAISE 0
                ENDIF
                MC%=ADDR(MC$)
                LOADR:(MC%,A$)

The machine code is:
                OS      AL$GRAB
                BCC     1$
                LDX     #0
        1$:
                RTS



       __________________
17.17  EXCEPTION HANDLING



         ______________
17.17.1  ERROR HANDLING


When an error is first detected the following actions are taken:

     1.  The error saved in RTB_EROR
     2.  If the TRAP flag is set then the language continues
     3.  The ON_ERR address for that procedure and each procedure above  is
         tested.   If  one  is  found to be non-zero, RTA_PC is set to that
         value and RTA_SP set to  the  BASE_SP  for  that  procedure.   The
         language then continues on.
     4.  If no error handling is detected then the error is reported  along
         with the name of the procedure in which the error was detected and
         the language exits.

If the error is ER_RT_UE (undefined external) then the externals which  are
undefined are displayed with DP$VIEW.

If the error is ER_RT_PN  (procedure  not  found)  then  the  name  of  the
procedure  not  found  is  displayed (as well as the procedure where it was
called).



         _____________
17.17.2  OUT OF MEMORY


Every time round the top loop the difference between RTA_SP and ALA_FREE is
calculated.   If this difference is less than 256 bytes, "OUT OF MEMORY" is
reported.  Note that no operand or operator can grow the stack by more than
256 bytes.

The filing system can also generate the "PACK FULL"  error  if  it  detects
that  after an operation fewer than 256 bytes will be free on device A.  In
this case it means essentially the same thing as "OUT OF MEMORY".

The only time when OPL uses memory, other than on the  stack,  is  when  it
opens files.  See section 17.11.2.



         ___________
17.17.3  LOW BATTERY


If the voltage goes  below  the  threshold  value  (5.2  volts)  while  the
language  is  running,  it is detected either in the top loop or during the
execution of an operator.  In either case  it  is  treated  as  a  standard
error.   If  no  error  handling is in force, the error is reported and the
machine turns off.

If the error is handled by an ONERR, the low battery error number is  saved
in  RTB_EROR.   It is not reported again by the top level until the battery
voltage has gone back above the minimum voltage.  This allows the procedure
to  take some action (e.g. to turn the organiser off).  If the procedure just
continues on the battery will eventually die completely and there is a risk
of having to cold boot the machine.

Note that the battery is more likely to drop below  the  threshold  voltage
when  devices,  such  as  the packs or the RS232 interface, are switched on
because they drain substantially more current than the Organiser by itself.
See  section  3.2 for more details of the power drain of different devices.
Also note that a battery naturally recovers some of its power  after  being
turned off for a while.



         ____________
17.17.4  ON/CLEAR KEY


In normal operation pressing the ON/CLEAR key results in the  execution  of
the language being frozen until another key is pressed.  If the key pressed
is 'Q','q' or '6' it creates an error condition ER_RT_BK.  If there  is  no
user error handling, execution of the language will terminate.

If ESCAPE OFF has been executed  then  the  ON/CLEAR  key  has  no  special
effect.

In an input statement then the ON/CLEAR key acts  in  one  of  3  different
ways:
     1.  If there is any input it is cleared
     2.  Or if the TRAP option has been used then the input exits with  the
         error condition ER_RT_BK
     3.  Otherwise it is ignored

See QCO_INPUT_INT, QCO_INPUT_NUM, QCO_INPUT_STR, RTF_GET, RTF_SGET, RTF_KEY
and RTF_SKEY.



         _______
17.17.5  WARNING


OPL is a powerful flexible language and as such it  has  the  potential  to
crash  the  operating  system  or  get  into  an  infinite  loop.   This is
particularly unfortunate in the case of the ORGANISER because all the  data
held  in  device  A:   is  lost  when  the machine re-boots.  For extensive
development of 'dangerous' routines a RAMPACK has a lot to recommend it.

There are trivial ways to crash such as poking system  variables  or  using
USR function with wrong addresses or bad machine code.  It is impossible to
describe all the other ways in which such problems can arise.  The examples
listed below show the most obvious ways in the simplest possible form.

     1.  ESCAPE OFF :DO :UNTIL 0        :REM Impossible to get out

     2.  WHILE GET :ENDWH               :REM Hard to get out of

     3.  DO :KEY :UNTIL 0               :REM Hard to get out of

     4.  A::  ONERR A::  :RAISE 0       :REM Impossible to get out

     5.  A::  ONERR A::  :DO :UNTIL 0   :REM Impossible to get out

Error handling is best added at the end of a  development  cycle.   Turning
ESCAPE  OFF substantially increases the chances of getting into an infinite
loop from which there is no exit.



       _________________
17.18  INDEX OF OPERANDS


00  QI_INT_SIM_FP       0D  QI_LS_INT_SIM_FP    1A  QI_INT_FLD
01  QI_NUM_SIM_FP       0E  QI_LS_NUM_SIM_FP    1B  QI_NUM_FLD
02  QI_STR_SIM_FP       0F  QI_LS_STR_SIM_FP    1C  QI_STR_FLD
03  QI_INT_ARR_FP       10  QI_LS_INT_ARR_FP    1D  QI_LS_INT_FLD
04  QI_NUM_ARR_FP       11  QI_LS_NUM_ARR_FP    1E  QI_LS_NUM_FLD
05  QI_STR_ARR_FP       12  QI_LS_STR_ARR_FP    1F  QI_LS_STR_FLD
06  QI_NUM_SIM_ABS      13  QI_LS_NUM_SIM_ABS   20  QI_STK_LIT_BYTE
07  QI_INT_SIM_IND      14  QI_LS_INT_SIM_IND   21  QI_STK_LIT_WORD
08  QI_NUM_SIM_IND      15  QI_LS_NUM_SIM_IND   22  QI_INT_CON
09  QI_STR_SIM_IND      16  QI_LS_STR_SIM_IND   23  QI_NUM_CON
0A  QI_INT_SIM_IND      17  QI_LS_INT_SIM_IND   24  QI_STR_CON
0B  QI_NUM_SIM_IND      18  QI_LS_NUM_SIM_IND
0C  QI_STR_SIM_IND      19  QI_LS_STR_SIM_IND



       __________________
17.19  INDEX OF OPERATORS


25  QCO_SPECIAL         47  QCO_GT_STR          69  QCO_USE
26  QCO_BREAK           48  QCO_GTE_STR         6A  QCO_KSTAT
27  QCO_LT_INT          49  QCO_NE_STR          6B  QCO_EDIT
28  QCO_LTE_INT         4A  QCO_EQ_STR          6C  QCO_INPUT_INT
29  QCO_GT_INT          4B  QCO_ADD_STR         6D  QCO_INPUT_NUM
2A  QCO_GTE_INT         4C  QCO_AT              6E  QCO_INPUT_STR
2B  QCO_NE_INT          4D  QCO_BEEP            6F  QCO_PRINT_INT
2C  QCO_EQ_INT          4E  QCO_CLS             70  QCO_PRINT_NUM
2D  QCO_ADD_INT         4F  QCO_CURSOR          71  QCO_PRINT_STR
2E  QCO_SUB_INT         50  QCO_ESCAPE          72  QCO_PRINT_SP
2F  QCO_MUL_INT         51  QCO_GOTO            73  QCO_PRINT_CR
30  QCO_DIV_INT         52  QCO_OFF             74  QCO_LPRINT_INT
31  QCO_POW_INT         53  QCO_ONERR           75  QCO_LPRINT_NUM
32  QCO_UMIN_INT        54  QCO_PAUSE           76  QCO_LPRINT_STR
33  QCO_NOT_INT         55  QCO_POKEB           77  QCO_LPRINT_SP
34  QCO_AND_INT         56  QCO_POKEW           78  QCO_LPRINT_CR
35  QCO_OR_INT          57  QCO_RAISE           79  QCO_RETURN
36  QCO_LT_NUM          58  QCO_RANDOMIZE       7A  QCO_RETURN_NOUGHT
37  QCO_LTE_NUM         59  QCO_STOP            7B  QCO_RETURN_ZERO
38  QCO_GT_NUM          5A  QCO_TRAP            7C  QCO_RETURN_NULL
39  QCO_GTE_NUM         5B  QCO_APPEND          7D  QCO_PROC
3A  QCO_NE_NUM          5C  QCO_CLOSE           7E  QCO_BRA_FALSE
3B  QCO_EQ_NUM          5D  QCO_COPY            7F  QCO_ASS_INT
3C  QCO_ADD_NUM         5E  QCO_CREATE          80  QCO_ASS_NUM
3D  QCO_SUB_NUM         5F  QCO_DELETE          81  QCO_ASS_STR
3E  QCO_MUL_NUM         60  QCO_ERASE           82  QCO_DROP_BYTE
3F  QCO_DIV_NUM         61  QCO_FIRST           83  QCO_DROP_WORD
40  QCO_POW_NUM         62  QCO_LAST            84  QCO_DROP_NUM
41  QCO_UMIN_NUM        63  QCO_NEXT            85  QCO_DROP_STR
42  QCO_NOT_NUM         64  QCO_BACK            86  QCO_INT_TO_NUM
43  QCO_AND_NUM         65  QCO_OPEN            87  QCO_NUM_TO_INT
44  QCO_OR_NUM          66  QCO_POSITION        88  QCO_END_FIELDS
45  QCO_LT_STR          67  QCO_RENAME          89  QCO_RUN_ASSEM
46  QCO_LTE_STR         68  QCO_UPDATE



       __________________
17.20  INDEX OF FUNCTIONS


8A  RTF_ADDR            A0  RTF_VIEW            B6  RTF_SPACE
8B  RTF_ASC             A1  RTF_YEAR            B7  RTF_DIR
8C  RTF_DAY             A2  RTF_COUNT           B8  RTF_CHR
8D  RTF_DISP            A3  RTF_EOF             B9  RTF_DATIM
8E  RTF_ERR             A4  RTF_EXIST           BA  RTF_SERR
8F  RTF_FIND            A5  RTF_POS             BB  RTF_FIX
90  RTF_FREE            A6  RTF_ABS             BC  RTF_GEN
91  RTF_GET             A7  RTF_ATAN            BD  RTF_SGET
92  RTF_HOUR            A8  RTF_COS             BE  RTF_HEX
93  RTF_IABS            A9  RTF_DEG             BF  RTF_SKEY
94  RTF_INT             AA  RTF_EXP             C0  RTF_LEFT
95  RTF_KEY             AB  RTF_FLT             C1  RTF_LOWER
96  RTF_LEN             AC  RTF_INTF            C2  RTF_MID
97  RTF_LOC             AD  RTF_LN              C3  RTF_NUM
98  RTF_MENU            AE  RTF_LOG             C4  RTF_RIGHT
99  RTF_MINUTE          AF  RTF_PI              C5  RTF_REPT
9A  RTF_MONTH           B0  RTF_RAD             C6  RTF_SCI
9B  RTF_PEEKB           B1  RTF_RND             C7  RTF_UPPER
9C  RTF_PEEKW           B2  RTF_SIN             C8  RTF_SUSR
9D  RTF_RECSIZE         B3  RTF_SQR             C9  RTF_SADDR
9E  RTF_SECOND          B4  RTF_TAN
9F  RTF_IUSR            B5  RTF_VAL



       ________
17.21  EXAMPLES


In these examples all values are given  in  hexadecimal;  word  values  are
given  as  4  digits,  bytes as 2 digits each one separated by a space.  If
values are undefined they are written as **.



         _________
17.21.1  EXAMPLE 1

Source code:
                EX1:
                LOCAL A$(5)
                A$="ABC"

The Q code header is:
High memory     0009            size of the variables on stack
                000A            length of Q code
                00              number of parameters
                                  type of parameter
                0000            size of global area
                                  global name
                                  global type
                                  offset
                0000            size of externals
                                  external name
                                  external type
                0003            bytes of string fix-ups
                FFF7              string fix-up offset (from FP)
                05                max length of string
Low memory      0000            bytes of array fix-ups
                                  array fix-up offset (from FP)
                                  size of array

The Q code is:
                0F FFF8         QI_LS_STR_SIM_FP
                24              QI_STR_CON
                03 41 42 43     "ABC"
                81              QCO_ASS_STR
                7B              QCO_RETURN_ZERO

If this program is run on a CM the stack looks like:

        Initially           Left Side   Constant    Assign      On Return
3EFF    '1'                 '1'         '1'         '1'         '1'
3EFE    'X'                 'X'         'X'         'X'         'X'
3EFD    'E'                 'E'         'E'         'E'         'E'
3EFC    ':'                 ':'         ':'         ':'         ':'
3EFB    'A'                 'A'         'A'         'A'         'A'
3EFA    05                  05          05          05          05
3EF9    00   - Top proc     00          00          00          00
3EF8    00   - No. paras    00          00          00          00
3EF6    3EF9 - Return PC    3EF9        3EF9        3EF9        3EF9
3EF4    0000 - ONERR        0000        0000        0000        0000
3EF2    3EDB - BASE SP      3EDB        3EDB        3EDB        3EDB
3EF0    0000 - FP           0000        0000        0000        0000
3EEE    3EEE - Global table 3EEE        3EEE        3EEE        3EEE
3EED    00                  00          00          00          00
3EEC    00                  00          00          00          00
3EEB    00                  00          'C'         'C'         'C'
3EEA    00                  00          'B'         'B'         'B'
3EE9    00                  00          'A'         'A'         'A'
3EE8    00                  00          03          03          03
3EE7    05                  05          05          05          05
3EE6    **                  **          **          **          **
3EE5    **                  **          **          **          **
3EE4    QCO_RETURN_ZERO    7B           7B          7B          7B
3EE3    QCO_ASS_STR         81          81          81          81
3EE2    'C'                 'C'         'C'         'C'         'C'
3EE1    'B'                 'B'         'B'         'B'         'B'
3EE0    'A'                 'A'         'A'         'A'         'A'
3EDF    03                  03          03          03          03
3EDE    QI_STR_CON          24          24          24          24
3EDC    FFF8                FFF8        FFF8        FFF8        FFF8
3EDB    QI_LS_STR_SIM_FP    0F          0F          0F          0F
3EDA    **                  3EE8        3EE8        **          00
3ED9    **                  05          05          **          00
3ED8    **                  00          00          **          00
3ED7    **                  **          'C'         **          00
3ED6    **                  **          'B'         **          00
3ED5    **                  **          'A'         **          00
3ED4    **                  **          03          **          00
3ED3    **                  **          **          **          00
3ED2    **                  **          **          **          00

FP      3EF0                3EF0        3EF0        3EF0
PC      3EDB                3EDE        3EE3        3EE4
SP      3EDB                3ED8        3ED4        3EDB



         _________
17.21.2  EXAMPLE 2

When a file is created the operator QCO_CREATE is followed by  the  logical
name  to  use  and the field type and names.  The list is terminated by the
operator QCO_END_FIELDS.

For example:

                CREATE "B:ABC",B,AAA$,B%,CC

is translated as the Q code:

                24                      QI_STR_CON
                05 42 3A 41 42 43       "B:ABC"
                5E                      QCO_CREATE
                01                      Logical name B
                02                      Type string
                04 41 41 41 24          "AAA$"
                00                      Type integer
                02 42 25                "B%"
                01                      Type floating point
                02 43 43                "CC"
                88                      QCO_END_FIELDS



         _________
17.21.3  EXAMPLE 3


The recursive example given in 17.12.1:

                RECURS:(I%)
                IF I%
                 RECURS:(I%-1)
                ENDIF

Looks like this on the stack:

        Address         Contents        Description

        3D5A            0010            Parameter
        3D59            00              Parameter type
        3D58            01              Number of parameters
        3D57            41              Device A
        3D55            3D6D            Return RTA_PC
        3D53            0000            ONERR address
        3D51            3D29            BASE SP
        3D4F            3D82            Previous FP
        3D4D            3D4D            Globals start address
        3D4B            3D5A            Indirect address to parameter
        3D49            **
        3D48            7B              QCO_RETURN_ZERO
        3D47            84              QCO_DROP_NUM
        3D40            "RECURS"
        3D3F            7D              QCO_PROC
        3D3E            01
        3D3D            20              QCO_STK_LIT_BYTE
        3D3C            00
        3D3B            20              QCO_STK_LIT_BYTE
        3D3A            2E              QCO_SUB_INT
        3D38            0001
        3D37            22              QI_INT_CON
        3D35            FFFC
        3D34            07              QI_INT_SIM_IND
        3D32            001B
        3D31            7E              QCO_BRA_FALSE
        3D2F            FFFC
        3D2E            07              QI_INT_SIM_IND
        3D2C            000F            Parameter for next call
        3D2B            00              parameter type
        3D2A            01              parameter count

Note that the top 4 byte and the bottom 4 bytes are almost identical,  this
is shown at the point where the procedure is about to be invoked:

        RTA_PC          3D3F
        RTA_SP          3D2A
        RTA_FP          3D4F



         _________
17.21.4  EXAMPLE 4

Source code:
                EX4:(PPP$)
                LOCAL A$(5)
                GLOBAL B,C%(3),D$(5)
                J$=PPP$

The Q code header is:
                0035            size of the variables on stack
                0008            size of Q code length
                01              number of parameters
                02                type of parameter
                0011            size of global area
                01 42             global name
                01                global type
                FFE1              offset
                02 43 25          global name
                03                global type
                FFD9              offset
                02 44 24          global name
                02                global type
                FFD3              offset
                0004            bytes of externals
                02 4A 24          external name
                02                external type
                0006            bytes of string fix-ups
                FFCB              string fix-up offset (from FP)
                05                max length of string
                FFD2              string fix-up offset (from FP)
                05                max length of string
                0004            bytes of array fix-ups
                FFD9              array fix-up offset (from FP)
                0003              size of array

The Q code is:
                16 FFE9         QI_LS_STR_SIM_IND
                09 FFEB         QI_STR_SIM_IND
                81              QCO_ASS_STR
                7B              QCO_RETURN_ZERO

If this program is run on a CM from the procedure:
                XXX:
                GLOBAL J$(3)
                EX4:("RST")

The stack looks like:
        3EFA            "A:XXX"
        3EF9            00                      Number of parameters
        3EF8            00                      Top procedure
        3EF6            3EF9                    Return PC
        3EF4            0000                    ONERR address
        3EF2            3ED1                    BASE SP
        3EF0            0000                    FP
        3EEE            3EE8                    Start of global table
        3EEC            3EE4                    Address of global
        3EEB            02                      Global type
        3EE8            "J$"                    Global name
        3EE3            03 00 00 00 00          Global J$
        3EE1            **
        3EE0            7B                      QCO_RETURN_ZERO
        3EDF            84                      QCO_DROP_NUM
        3EDB            "EX4"
        3EDA            7D                      QCO_PROC
        3ED8            20 01                   QI_STK_LIT_BYTE
        3ED6            20 02                   QI_STK_LIT_BYTE
        3ED2            "RST"
        3ED1            24                      QI_STR_CON
        3ECD            "RST"                   Parameter
        3ECC            02                      Parameter type
        3ECB            01                      Number of parameters
        3ECA            00                      Device A:
        3EC8            3EDA                    Return PC
        3EC6            0000                    ONERR
        3EC4            3E83                    BASE SP
        3EC2            3EF0                    FP
        3EC0            3EAF                    Start global table
        3EBE            3E95
        3EBD            02
        3EBA            02 44 24                Global D$
        3EB8            3E9B
        3EB7            03
        3EB4            02 43 25                Global C%()
        3EB2            3EA3
        3EB1            01
        3EAF            01 42                   Global B
        3EAD            3ECD                    Indirection to PPP$
        3EAB            3EE4                    Indirection to J$
        3EA3            00 00 00 00 00 00 00 00         GLOBAL B
        3E9B            00 03 00 00 00 00 00 00         GLOBAL C%()
        3E94            05 00 00 00 00 00 00            GLOBAL D$
        3E8D            05 00 00 00 00 00 00            LOCAL A$
        3E8B            **
        3E8A            7B                      QCO_RETURN_ZERO
        3E89            81                      QCO_ASS_STR
        3E87            FFEB
        3E86            09                      QI_STR_SIM_IND
        3E84            FFE9
        3E83            16                      QI_LS_STR_SIM_IND

When running EX4 the offset FFE9 is added to RTA_FP (3EC2)  to  give  3EAB.
The  address  at  3EAB is 3EE4 which is the address of the global J$.  This
address with a non-field flag is  stacked.   Similarly  FFEB  is  added  to
RTA_FP  to  give  3EAD, which contains the address 3ECD, the address of the
parameter PPP$.



         _________
17.21.5  EXAMPLE 5


Source code:
                TOP:
                PRINT ABC:(GET)
                GET


                ABC:(N%)
                RETURN(N%*N%)

At the point when ABC: has just been called the stack looks like:

3EFA            "A:TOP"
3EF9            00              NO. of parameters
3EF8            00              Top procedure
3EF6            3EF9            Return PC
3EF4            0000            ONERR address
3EF2            3EDD            BASE SP
3EF0            0000            FP
3EEE            3EEE            Global table
3EEC            **
3EEB            7B              QCO_RETURN_ZERO
3EEA            83              QCO_DROP_WORD
3EE9            91              RTF_GET
3EE8            73              QCO_PRINT_CR
3EE7            70              QCO_PRINT_NUM
3EE3            "ABC"
3EE2            7D              QCO_PROC
3EE0            20 01           QI_STK_LIT_BYTE
3EDE            20 00           QI_STK_LIT_BYTE
3EDD            91              RTF_GET
3EDB            0020
3EDA            00              Integer
3ED9            01              No. parameters
3ED8            41              Device A:
3ED6            3EE2            Return PC
3ED4            0000            ONERR
3ED2            3EC1            BASE SP
3ED0            3EF0            FP
3ECE            3ECE            global table
3ECC            3EE4            Address of N%
3ECA            **
3EC9            79              QCO_RETURN
3EC8            86              QCO_INT_TO_NUM
3EC7            2F              QCO_MUL_INT
3EC4            07 FFF7         QI_INT_SIM_IND
3EC1            07 FFF7         QI_INT_SIM_IND
3EBF            0020                    0400                    0300
3EBD            0020                    **                      1024
3EBB            **                      **                      0000
3EB9            **                      **                      0000

PC              3EC7                    3EC8                    3EC9