@database beginner.guide

@Master beginner

@Width 75


This is the AmigaGuideŽ file beginner.guide, produced by Makeinfo-1.55 from 
the input file beginner.


@Node Main "beginner.guide"
@{" Search " SYSTEM "RUN SearchGuide :beginner.guide"}


   Copyright (c) 1994-1995, Jason R. Hulance.

A Beginner's Guide to Amiga E
*****************************

   This Guide gives an introduction to the Amiga E programming language
and, to some extent, programming in general.


Part One:    Getting Started

 @{" Introduction to Amiga E " Link "Introduction to Amiga E"} 
 @{" Understanding a Simple Program " Link "Understanding a Simple Program"} 
 @{" Variables and Expressions " Link "Variables and Expressions"} 
 @{" Program Flow Control " Link "Program Flow Control"} 
 @{" Summary " Link "Summary"} 

Part Two:    The E Language

 @{" Format and Layout " Link "Format and Layout"} 
 @{" Procedures and Functions " Link "Procedures and Functions"} 
 @{" Constants " Link "Constants"} 
 @{" Types " Link "Types"} 
 @{" More About Statements and Expressions " Link "More About Statements and Expressions"} 
 @{" E Built-In Constants Variables and Functions " Link "E Built-In Constants Variables and Functions"} 
 @{" Modules " Link "Modules"} 
 @{" Exception Handling " Link "Exception Handling"} 
 @{" Memory Allocation " Link "Memory Allocation"} 
 @{" Floating-Point Numbers " Link "Floating-Point Numbers"} 
 @{" Recursion " Link "Recursion"} 
 @{" Object Oriented E " Link "Object Oriented E"} 

Part Three:  Worked Examples

 @{" Introduction to the Examples " Link "Introduction to the Examples"} 
 @{" String Handling and I-O " Link "String Handling and I-O"} 
 @{" Timing Expressions " Link "Timing Expressions"} 
 @{" Argument Parsing " Link "Argument Parsing"} 
 @{" Gadgets IDCMP and Graphics " Link "Gadgets IDCMP and Graphics"} 
 @{" Recursion Example " Link "Recursion Example"} 

Part Four:   Appendices

 @{" Common Problems " Link "Common Problems"} 
 @{" Other Information " Link "Other Information"} 

Indices

 @{" E Language Index " Link "E Language Index"} 
 @{" Main Index " Link "Main Index"} 


@EndNode

@Node "Introduction to Amiga E" "beginner.guide/Introduction to Amiga E"
@Next "Understanding a Simple Program"
@Prev "Main"
@Toc "Main"

Introduction to Amiga E
***********************

   To interact with your Amiga you need to speak a language it understands.
Luckily, there is a wide choice of such languages, each of which fits a
particular need.  For instance, BASIC (in most of its flavours) is simple
and easy to learn, and so is ideal for beginners.  Assembly, on the other
hand, requires a lot of effort and is quite tedious, but can produce the
fastest programs so is generally used by commercial programmers.  These
are two extremes and most businesses and colleges use C or
Pascal/Modula-2, which try to strike a balance between simplicity and
speed.

   E programs look very much like Pascal or Modula-2 programs, but E is
based more closely on C. Anyone familiar with these languages will easily
learn E, only really needing to get to grips with E's unique features and
those borrowed from other languages.  This guide is aimed at people who
haven't done much programming and may be too trivial for competent
programmers, who should find the `E Reference Manual' more than adequate
(although some of the later sections offer different explanations to the
@{b}Reference Manual@{ub}, which may prove useful).

   Part One (this part) goes through some of the basics of the E language
and programming in general.  Part Two delves deeper into E, covering the
more complex topics and the unique features of E. Part Three goes through
a few example programs, which are a bit longer than the examples in the
other Parts.  Finally, Part Four contains the Appendices, which is where
you'll find some other, miscellaneous information.


 @{" A Simple Program " Link "A Simple Program"} 


@EndNode

@Node "A Simple Program" "beginner.guide/A Simple Program"
@Toc "Introduction to Amiga E"

A Simple Program
================

   If you're still reading you're probably desperate to do some
programming in E but you don't know how to start.  We'll therefore jump
straight in the deep end with a small example.  You'll need to know two
things before we start: how to use a text editor and the Shell/CLI.


 @{" The code " Link "The code"} 
 @{" Compilation " Link "Compilation"} 
 @{" Execution " Link "Execution"} 


@EndNode

@Node "The code" "beginner.guide/The code"
@Next "Compilation"
@Toc "A Simple Program"

The code
--------

   Enter the following lines of code into a text editor and save it as the
file @{b}simple.e@{ub} (taking care to copy each line accurately).  (Just type the
characters shown, and at the end of each line press the RETURN or ENTER
key.)

     PROC main()
       WriteF('My first program')
     ENDPROC

Don't try to do anything different, yet, to the code: the case of the
letters in each word is significant and the funny characters are important.
If you're a real beginner you might have difficulty finding the '
character.  On my GB keyboard it's on the big key in the top left-hand
corner directly below the ESC key.  On a US and most European keyboards
it's two to the right of the L key, next to the ; key.


@EndNode

@Node "Compilation" "beginner.guide/Compilation"
@Next "Execution"
@Prev "The code"
@Toc "A Simple Program"

Compilation
-----------

   Once the file is saved (preferably in the RAM disk, since it's only a
small program), you can use the E compiler to turn it into an executable
program.  All you need is the file @{b}ec@{ub} in your @{b}C:@{ub} directory or somewhere
else on your search path (advanced users note: we don't need the @{b}Emodules:@{ub}
assignment because we aren't using any modules).  Assuming you have this
and you have a Shell/CLI running, enter the following at the prompt after
changing directory to where you saved your new file:

     ec simple

If all's well you should be greeted, briefly, by the E compiler.  If
anything went wrong then double-check the contents of the file @{b}simple.e@{ub},
that your CLI is in the same directory as this file, and that the program
@{b}ec@{ub} is in your @{b}C:@{ub} directory (or on your search path).


@EndNode

@Node "Execution" "beginner.guide/Execution"
@Prev "Compilation"
@Toc "A Simple Program"

Execution
---------

   Once everything is working you can run your first program by entering
the following at the CLI prompt:

     simple

   As a help here's the complete transcript of the whole compilation and
execution process (the CLI prompt, below, is the bit of text beginning
with @{b}1.@{ub} and ending in @{b}>@{ub}):

     1.System3.0:> cd ram:
     1.Ram Disk:> ec simple
     Amiga E Compiler/Assembler/Linker/PP v3.1a registered (c) '91-95 Wouter
     lexical analysing ...
     parsing and compiling ...
     no errors
     1.Ram Disk:> simple
     My first program1.Ram Disk:>

Your display should be something similar if it's all worked.  Notice how
the output from the program runs into the prompt (the last line).  We'll
fix this soon.


@EndNode

@Node "Understanding a Simple Program" "beginner.guide/Understanding a Simple Program"
@Next "Variables and Expressions"
@Prev "Introduction to Amiga E"
@Toc "Main"

Understanding a Simple Program
******************************

   To understand the example program we need to understand quite a few
things.  The observant amongst you will have noticed that all it does is
print out a message, and that message was part of a line we wrote in the
program.  The first thing to do is see how to change this message.


 @{" Changing the Message " Link "Changing the Message"} 
 @{" Procedures " Link "Procedures"} 
 @{" Parameters " Link "Parameters"} 
 @{" Strings " Link "Strings"} 
 @{" Style Reuse and Readability " Link "Style Reuse and Readability"} 
 @{" The Simple Program " Link "The Simple Program"} 


@EndNode

@Node "Changing the Message" "beginner.guide/Changing the Message"
@Next "Procedures"
@Toc "Understanding a Simple Program"

Changing the Message
====================

   Edit the file so that line contains a different message between the two
' characters and compile it again using the same procedure as before.
Don't use any ' characters except those around the message.  If all went
well, when you run the program again it should produce a different message.
If something went wrong, compare the contents of your file with the
original and make sure the only difference is the message between the '
characters.


 @{" Tinkering with the example " Link "Tinkering with the example"} 
 @{" Brief overview " Link "Brief overview"} 


@EndNode

@Node "Tinkering with the example" "beginner.guide/Tinkering with the example"
@Next "Brief overview"
@Toc "Changing the Message"

Tinkering with the example
--------------------------

   Simple tinkering is a good way to learn for yourself so it is
encouraged on these simple examples.  Don't stray too far, though, and if
you start getting confused return to the proper example pretty sharpish!


@EndNode

@Node "Brief overview" "beginner.guide/Brief overview"
@Prev "Tinkering with the example"
@Toc "Changing the Message"

Brief overview
--------------

   We'll look in detail at the important parts of the program in the
following sections, but we need first to get a glimpse of the whole
picture.  Here's a brief description of some fundamental concepts:

   @{b}*@{ub}     @{i}Procedures:@{ui} We defined a procedure called @{b}main@{ub} and used the
     (built-in) procedure @{b}WriteF@{ub}.  A procedure can be thought of as a
     small program with a name.

   @{b}*@{ub}     @{i}Parameters:@{ui} The message in parentheses after @{b}WriteF@{ub} in our
     program is the parameter to @{b}WriteF@{ub}.  This is the data which the
     procedure should use.

   @{b}*@{ub}     @{i}Strings:@{ui} The message we passed to @{b}WriteF@{ub} was a series of
     characters enclosed in ' characters.  This is known as a @{fg shine}string@{fg text}.


@EndNode

@Node "Procedures" "beginner.guide/Procedures"
@Next "Parameters"
@Prev "Changing the Message"
@Toc "Understanding a Simple Program"

Procedures
==========

   As mentioned above, a procedure can be thought of as a small program
with a name.  In fact, when an E program is run the procedure called @{b}main@{ub}
is executed.  Therefore, if your E program is going to do anything you
must define a @{b}main@{ub} procedure.  Other (built-in or user-defined) procedures
may be run (or @{fg shine}called@{fg text}) from this procedure (as we did @{b}WriteF@{ub} in the
example).  For instance, if the procedure @{b}fred@{ub} calls the procedure @{b}barney@{ub}
the code (or mini-program) associated with @{b}barney@{ub} is executed.  This may
involve calls to other procedures, and when the execution of this code is
complete the next piece of code in the procedure @{b}fred@{ub} is executed (and
this is generally the next line of the procedure).  When the end of the
procedure @{b}main@{ub} has been reached the program has finished.  However, lots
can happen between the beginning and end of a procedure, and sometimes the
program may never get to finish.  Alternatively, the program may @{fg shine}crash@{fg text},
causing strange things to happen to your computer.


 @{" Procedure Definition " Link "Procedure Definition"} 
 @{" Procedure Execution " Link "Procedure Execution"} 
 @{" Extending the example " Link "Extending the example"} 


@EndNode

@Node "Procedure Definition" "beginner.guide/Procedure Definition"
@Next "Procedure Execution"
@Toc "Procedures"

Procedure Definition
--------------------

   Procedures are defined using the keyword @{b}PROC@{ub}, followed by the new
procedure's name (in lowercase letters), a description of the parameters
it takes (in parentheses), a series of lines forming the code of the
procedure and then the keyword @{b}ENDPROC@{ub}.  Look at the example program again
to identify the various parts.  See @{"The code" Link "The code"}.


@EndNode

@Node "Procedure Execution" "beginner.guide/Procedure Execution"
@Next "Extending the example"
@Prev "Procedure Definition"
@Toc "Procedures"

Procedure Execution
-------------------

   Procedures can be called (or executed) from within the code part of
another procedure.  You do this by giving its name, followed by some data
in parentheses.  Look at the call to @{b}WriteF@{ub} in the example program.  See
@{"The code" Link "The code"}.


@EndNode

@Node "Extending the example" "beginner.guide/Extending the example"
@Prev "Procedure Execution"
@Toc "Procedures"

Extending the example
---------------------

   Here's how we could change the example program to define another
procedure:

     PROC main()
       WriteF('My first program')
       fred()
     ENDPROC
     
     PROC fred()
       WriteF('...slightly improved')
     ENDPROC

This may seem complicated, but in fact it's very simple.  All we've done
is define a second procedure called @{b}fred@{ub} which is just like the original
program--it outputs a message.  We've @{fg shine}called@{fg text} this procedure in the @{b}main@{ub}
procedure just after the line which outputs the original message.
Therefore, the message in @{b}fred@{ub} is output after this message.  Compile the
program as before and run it so you don't have to take my word for it.


@EndNode

@Node "Parameters" "beginner.guide/Parameters"
@Next "Strings"
@Prev "Procedures"
@Toc "Understanding a Simple Program"

Parameters
==========

   Generally we want procedures to work with particular data.  In our
example we wanted the @{b}WriteF@{ub} procedure to work on a particular message.
We passed the message as a @{fg shine}parameter@{fg text} (or @{fg shine}argument@{fg text}) to @{b}WriteF@{ub} by
putting it between the parentheses (the @{b}(@{ub} and @{b})@{ub} characters) that follow
the procedure name.  When we called the @{b}fred@{ub} procedure, however, we did
not require it to use any data so the parentheses were left empty.

   When defining a procedure when define how much and what type of data we
want it to work on, and when calling a procedure we give the specific data
it should use.  Notice that the procedure @{b}fred@{ub} (like the procedure @{b}main@{ub})
has empty parentheses in its definition.  This means that the procedure
cannot be given any data as parameters when it is called.  Before we can
define our own procedure that takes parameters we must learn about
variables.  We'll do this in the next chapter.  See
@{"Global and local variables" Link "Global and local variables"}.


@EndNode

@Node "Strings" "beginner.guide/Strings"
@Next "Style Reuse and Readability"
@Prev "Parameters"
@Toc "Understanding a Simple Program"

Strings
=======

   A series of characters between two ' characters is known as a string.
Almost any character can be used in a string, although the \ and '
characters have a special meaning.  For instance, a linefeed is denoted by
the two characters @{b}\n@{ub}.  We now know how to stop the message running into
the prompt.  Change the program to be:

     PROC main()
       WriteF('My first program\n')
       fred()
     ENDPROC
     
     PROC fred()
       WriteF('...slightly improved\n')
     ENDPROC

Compile it as before, and run it.  You should notice that the messages now
appear on lines by themselves, and the second message is separated from
the prompt which follows it.  We have therefore cured the linefeed problem
we spotted earlier (see @{"Execution" Link "Execution"}).


@EndNode

@Node "Style Reuse and Readability" "beginner.guide/Style Reuse and Readability"
@Next "The Simple Program"
@Prev "Strings"
@Toc "Understanding a Simple Program"

Style, Reuse and Readability
============================

   The example has grown into two procedures, one called @{b}main@{ub} and one
called @{b}fred@{ub}.  However, we could get by with only one procedure:

     PROC main()
       WriteF('My first program\n')
       WriteF('...slightly improved\n')
     ENDPROC

   What we've done is replace the call to the procedure @{b}fred@{ub} with the code
it represents (this is called @{fg shine}inlining@{fg text} the procedure).  In fact, almost
all programs can be easily re-written to eliminate all but the @{b}main@{ub}
procedure.  However, splitting a program up using procedures normally
results in more readable code.  It is also helpful to name your procedures
so that their function is apparent, so our procedure @{b}fred@{ub} should probably
have been named @{b}message@{ub} or something similar.  A well-written program in
this style can read just like English (or any other spoken language).

   Another reason for having procedures is to reuse code, rather than
having to write it out every time you use it.  Imagine you wanted to print
the same, long message fairly often in your program--you'd either have to
write it all out every time, or you could write it once in a procedure and
call this procedure when you wanted the message printed.  Using a
procedure also has the benefit of having only one copy of the message to
change, should it ever need changing.


@EndNode

@Node "The Simple Program" "beginner.guide/The Simple Program"
@Prev "Style Reuse and Readability"
@Toc "Understanding a Simple Program"

The Simple Program
==================

   The simple program should now (hopefully) seem simple.  The only bit
that hasn't been explained is the built-in procedure @{b}WriteF@{ub}.  E has many
built-in procedures and later we'll meet some of them in detail.  The
first thing we need to do, though, is manipulate data.  This is really
what a computer does all the time--it accepts data from some source
(possibly the user), manipulates it in some way (possibly storing it
somewhere, too) and outputs new data (usually to a screen or printer).
The simple example program did all this, except the first two stages were
rather trivial.  You told the computer to execute the compiled program
(this was some user input) and the real data (the message to be printed)
was retrieved from the program.  This data was manipulated by passing it
as a parameter to @{b}WriteF@{ub}, which then did some clever stuff to print it on
the screen.  To do our own manipulation of data we need to learn about
variables and expressions.


@EndNode

@Node "Variables and Expressions" "beginner.guide/Variables and Expressions"
@Next "Program Flow Control"
@Prev "Understanding a Simple Program"
@Toc "Main"

Variables and Expressions
*************************

   Anybody who's done any school algebra will probably know what a
variable is--it's just a named piece of data.  In algebra the data is
usually a number, but in E it can be all sorts of things (e.g., a string).
The manipulation of data like the addition of two numbers is known as an
@{fg shine}expression@{fg text}.  The result of an expression can be used to build bigger
expressions.  For instance, @{b}1+2@{ub} is an expression, and so is @{b}6-(1+2)@{ub}.  The
good thing is you can use variables in place of data in expressions, so if
@{b}x@{ub} represents the number 1 and @{b}y@{ub} represents 5, then the expression @{b}y-x@{ub}
represents the number 4.  In the next two sections we'll look at what kind
of variables you can define and what the different sorts of expressions
are.


 @{" Variables " Link "Variables"} 
 @{" Expressions " Link "Expressions"} 


@EndNode

@Node "Variables" "beginner.guide/Variables"
@Next "Expressions"
@Toc "Variables and Expressions"

Variables
=========

   Variables in E can hold many different kinds of data (called @{fg shine}types@{fg text}).
However, before a variable can be used it must be defined, and this is
known as @{fg shine}declaring@{fg text} the variable.  A variable declaration also decides
whether the variable is available for the whole program or just during the
code of a procedure (i.e., whether the variable is @{fg shine}global@{fg text} or @{fg shine}local@{fg text}).
Finally, the data stored in a variable can be changed using @{fg shine}assignments@{fg text}.
The following sections discuss these topics in slightly more detail.


 @{" Variable types " Link "Variable types"} 
 @{" Variable declaration " Link "Variable declaration"} 
 @{" Assignment " Link "Assignment"} 
 @{" Global and local variables " Link "Global and local variables"} 
 @{" Changing the example " Link "Changing the example"} 


@EndNode

@Node "Variable types" "beginner.guide/Variable types"
@Next "Variable declaration"
@Toc "Variables"

Variable types
--------------

   In E a variable is a storage place for data (and this storage is part
of the Amiga's RAM).  Different kinds of data may require different
amounts of storage.  However, data can be grouped together in @{fg shine}types@{fg text}, and
two pieces of data from the same type require the same amount of storage.
Every variable has an associated type and this dictates the maximum amount
of storage it uses.  Most commonly, variables in E store data from the
type @{b}LONG@{ub}.  This type contains the integers from -2,147,483,648 to
2,147,483,647, so is normally more than sufficient.  There are other
types, such as @{b}INT@{ub} and @{b}LIST@{ub}, and more complex things to do with types, but
for now knowing about @{b}LONG@{ub} is enough.


@EndNode

@Node "Variable declaration" "beginner.guide/Variable declaration"
@Next "Assignment"
@Prev "Variable types"
@Toc "Variables"

Variable declaration
--------------------

   Variables must be declared before they can be used.  They are declared
using the @{b}DEF@{ub} keyword followed by a (comma-separated) list of the names of
the variables to be declared.  These variables will all have type @{b}LONG@{ub}
(later we will see how to declare variables with other types).  Some
examples will hopefully make things clearer:

     DEF x
     
     DEF a, b, c

The first line declares the single variable @{b}x@{ub}, whilst the second declares
the variables @{b}a@{ub}, @{b}b@{ub} and @{b}c@{ub} all in one go.


@EndNode

@Node "Assignment" "beginner.guide/Assignment"
@Next "Global and local variables"
@Prev "Variable declaration"
@Toc "Variables"

Assignment
----------

   The data stored by variables can be changed and this is normally done
using @{fg shine}assignments@{fg text}.  An assignment is formed using the variable's name
and an expression denoting the new data it is to store.  The symbol @{b}:=@{ub}
separates the variable from the expression.  For example, the following
code stores the number two in the variable @{b}x@{ub}.  The left-hand side of the
@{b}:=@{ub} is the name of the variable to be affected (@{b}x@{ub} in this case) and the
right-hand side is an expression denoting the new value (simply the number
two in this case).

     x := 2

The following, more complex example uses the value stored in the variable
before the assignment as part of the expression for the new data.  The
value of the expression on the right-hand side of the @{b}:=@{ub} is the value
stored in the variable @{b}x@{ub} plus one.  This value is then stored in @{b}x@{ub},
over-writing the previous data.  (So, the overall effect is that @{b}x@{ub} is
incremented.)

     x := x + 1

This may be clearer in the next example which does not change the data
stored in @{b}x@{ub}.  In fact, this piece of code is just a waste of CPU time,
since all it does is look up the value stored in @{b}x@{ub} and store it back there!

     x := x


@EndNode

@Node "Global and local variables" "beginner.guide/Global and local variables"
@Next "Changing the example"
@Prev "Assignment"
@Toc "Variables"

Global and local variables (and procedure parameters)
-----------------------------------------------------

   There are two kinds of variable: @{fg shine}global@{fg text} and @{fg shine}local@{fg text}.  Data stored by
global variables can be read and changed by all procedures, but data
stored by local variables can only be accessed by the procedure to which
they are local.  Global variables must be declared before the first
procedure definition.  Local variables are declared within the procedure
to which they are local (i.e., between the @{b}PROC@{ub} and @{b}ENDPROC@{ub}).  For
example, the following code declares a global variable @{b}w@{ub} and local
variables @{b}x@{ub} and @{b}y@{ub}.

     DEF w
     
     PROC main()
       DEF x
       x:=2
       w:=1
       fred()
     ENDPROC
     
     PROC fred()
       DEF y
       y:=3
       w:=2
     ENDPROC

The variable @{b}x@{ub} is local to the procedure @{b}main@{ub}, and @{b}y@{ub} is local to @{b}fred@{ub}.
The procedures @{b}main@{ub} and @{b}fred@{ub} can read and alter the value of the global
variable @{b}w@{ub}, but @{b}fred@{ub} cannot read or alter the value of @{b}x@{ub} (since that
variable is local to @{b}main@{ub}).  Similarly, @{b}main@{ub} cannot read or alter @{b}y@{ub}.

   The local variables of one procedure are, therefore, completely
different to the local variables of another procedure.  For this reason
they can share the same names without confusion.  So, in the above
example, the local variable @{b}y@{ub} in @{b}fred@{ub} could have been called @{b}x@{ub} and the
program would have done exactly the same thing.

     DEF w
     
     PROC main()
       DEF x
       x:=2
       w:=1
       fred()
     ENDPROC
     
     PROC fred()
       DEF x
       x:=3
       w:=2
     ENDPROC

This works because the @{b}x@{ub} in the assignment in @{b}fred@{ub} can refer only to the
local variable @{b}x@{ub} of @{b}fred@{ub} (the @{b}x@{ub} in @{b}main@{ub} is local to @{b}main@{ub} so cannot be
accessed from @{b}fred@{ub}).

   If a local variable for a procedure has the same name as a global
variable then in the rest of the procedure the name refers only to the
local variable.  Therefore, the global variable cannot be accessed in the
procedure, and this is called @{fg shine}descoping@{fg text} the global variable.

   The parameters of a procedure are local variables for that procedure.
We've seen how to pass values as parameters when a procedure is called
(the use of @{b}WriteF@{ub} in the example), but until now we haven't been able to
define a procedure which takes parameters.  Now we know a bit about
variables we can have a go:

     DEF y
     
     PROC onemore(x)
       y:=x+1
     ENDPROC

This isn't a complete program so don't try to compile it.  Basically,
we've declared a variable @{b}y@{ub} (which will be of type @{b}LONG@{ub}) and a procedure
@{b}onemore@{ub}.  The procedure is defined with a parameter @{b}x@{ub}, and this is just
like a (local) variable declaration.  When @{b}onemore@{ub} is called a parameter
must be supplied, and this value is stored in the (local) variable @{b}x@{ub}
before execution of @{b}onemore@{ub}'s code.  The code stores the value of @{b}x@{ub} plus
one in the (global) variable @{b}y@{ub}.  The following are some examples of
calling @{b}onemore@{ub}:

       onemore(120)
       onemore(52+34)
       onemore(y)

   A procedure can be defined to take any number of parameters.  Below,
the procedure @{b}addthem@{ub} is defined to take two parameters, @{b}a@{ub} and @{b}b@{ub}, so it
must therefore be called with two parameters.  Notice that values stored
by the parameter variables (@{b}a@{ub} and @{b}b@{ub}) can be changed within the code of the
procedure.

     DEF y
     
     PROC addthem(a, b)
       a:=a+2
       y:=a*b
     ENDPROC

The following are some examples of calling @{b}addthem@{ub}:

       addthem(120,-20)
       addthem(52,34)
       addthem(y,y)


@EndNode

@Node "Changing the example" "beginner.guide/Changing the example"
@Prev "Global and local variables"
@Toc "Variables"

Changing the example
--------------------

   Before we change the example we must learn something about @{b}WriteF@{ub}.  We
already know that the characters @{b}\n@{ub} in a string mean a linefeed.  However,
there are several other important combinations of characters in a string,
and some are special to procedures like @{b}WriteF@{ub}.  One such combination is
@{b}\d@{ub}, which is easier to describe after we've seen the changed example.

     PROC main()
       WriteF('My first program\n')
       fred()
     ENDPROC
     
     PROC fred()
       WriteF('...brought to you by the number \d\n', 236)
     ENDPROC

You might be able to guess what happens, but compile it and try it out
anyway.  If everything's worked you should see that the second message
prints out the number that was passed as the second parameter to @{b}WriteF@{ub}.
That's what the @{b}\d@{ub} combination does--it marks the place in the string
where the number should be printed.  Here's the output the example should
generate:

     My first program
     ...brought to you by the number 236

Try this next change:

     PROC main()
       WriteF('My first program\n')
       fred()
     ENDPROC
     
     PROC fred()
       WriteF('...the number \d is quite nice\n', 16)
     ENDPROC

This is very similar, and just shows that the @{b}\d@{ub} really does mark the
place where the number is printed.  Again, here's the output it should
generate:

     My first program
     ...the number 16 is quite nice

We'll now try printing two numbers.

     PROC main()
       WriteF('My first program\n')
       fred()
     ENDPROC
     
     PROC fred()
       WriteF('...brought to you by the numbers \d and \d\n', 16, 236)
     ENDPROC

Because we're printing two numbers we need two lots of @{b}\d@{ub}, and we need to
supply two numbers as parameters in the order in which we want them to be
printed.  The number 16 will therefore be printed before the word `and'
and before the number 236.  Here's the output:

     My first program
     ...brought to you by the numbers 16 and 236

   We can now make a big step forward and pass the numbers as parameters
to the procedure @{b}fred@{ub}.  Just look at the differences between this next
example and the previous one.

     PROC main()
       WriteF('My first program\n')
       fred(16, 236)
     ENDPROC
     
     PROC fred(a,b)
       WriteF('...brought to you by the numbers \d and \d\n', a,b)
     ENDPROC

This time we pass the (local) variables @{b}a@{ub} and @{b}b@{ub} to @{b}WriteF@{ub}.  This is
exactly the same as passing the values they store (which is what the
previous example did), and so the output will be the same.  In the next
section we'll manipulate the variables by doing some arithmetic with @{b}a@{ub} and
@{b}b@{ub}, and get @{b}WriteF@{ub} to print the results.


@EndNode

@Node "Expressions" "beginner.guide/Expressions"
@Prev "Variables"
@Toc "Variables and Expressions"

Expressions
===========

   The E language includes the normal mathematical and logical operators.
These operators are combined with values (usually in variables) to give
@{fg shine}expressions@{fg text} which yield new values.  The following sections discuss this
topic in more detail.


 @{" Mathematics " Link "Mathematics"} 
 @{" Logic and comparison " Link "Logic and comparison"} 
 @{" Precedence and grouping " Link "Precedence and grouping"} 


@EndNode

@Node "Mathematics" "beginner.guide/Mathematics"
@Next "Logic and comparison"
@Toc "Expressions"

Mathematics
-----------

   All the standard mathematical operators are supported in E. You can do
addition, subtraction, multiplication and division.  Other functions such
as sine, modulus and square-root can also be used as they are part of the
Amiga system libraries, but we only need to know about simple mathematics
at the moment.  The @{b}+@{ub} character is used for addition, @{b}-@{ub} for subtraction, @{b}*@{ub}
for multiplication (it's the closest you can get to a multiplication sign
on a keyboard without using the letter @{b}x@{ub}), and @{b}/@{ub} for division (be careful
not to confuse the @{b}\ @{ub} used in strings with @{b}/@{ub} used for division).  The
following are examples of expressions:

       1+2+3+4
       15-5
       5*2
       330/33
       -10+20
       3*3+1

Each of these expressions yields ten as its result.  The last example is
very carefully written to get the precedence correct (see
@{"Precedence and grouping" Link "Precedence and grouping"}).

   All the above expressions use integer operators, so they manipulate
integers, giving integers as results.  @{fg shine}Floating-point@{fg text} numbers are also
supported by E, but using them is quite complicated (see
@{"Floating-Point Numbers" Link "Floating-Point Numbers"}).  (Floating-point numbers can represent both very
small fractions and very large integers, but they have a limited accuracy,
i.e., a limited number of @{i}significant@{ui} digits.)


@EndNode

@Node "Logic and comparison" "beginner.guide/Logic and comparison"
@Next "Precedence and grouping"
@Prev "Mathematics"
@Toc "Expressions"

Logic and comparison
--------------------

   Logic lies at the very heart of a computer.  They rarely guess what to
do next; instead they rely on hard facts and precise reasoning.  Consider
the password protection on most games.  The computer must decide whether
you entered the correct number or word before it lets you play the game.
When you play the game it's constantly making decisions: did your laser
hit the alien, have you got any lives left, etc.  Logic controls the
operation of a program.

   In E, the constants @{b}TRUE@{ub} and @{b}FALSE@{ub} represent the truth values true and
false (respectively), and the operators @{b}AND@{ub} and @{b}OR@{ub} are the standard logic
operators.  The comparison operators are @{b}=@{ub} (equal to), @{b}>@{ub} (greater than), @{b}<@{ub}
(less than), @{b}>=@{ub} (greater than or equal to), @{b}<=@{ub} (less than or equal to) and
@{b}<>@{ub} (not equal to).  All the following expressions are true:

       TRUE
       TRUE AND TRUE
       TRUE OR FALSE
       1=1
       2>1
       3<>0

And these are all false:

       FALSE
       TRUE AND FALSE
       FALSE OR FALSE
       0=2
       2<1
       (2<1) AND (-1=0)

The last example must use parentheses.  We'll see why in the next section
(it's to do with precedence, again).

   The truth values @{b}TRUE@{ub} and @{b}FALSE@{ub} are actually numbers.  This is how the
logic system works in E. @{b}TRUE@{ub} is the number -1 and @{b}FALSE@{ub} is zero.  The
logic operators @{b}AND@{ub} and @{b}OR@{ub} expect such numbers as their parameters.  In
fact, the @{b}AND@{ub} and @{b}OR@{ub} operators are really bit-wise operators (see
@{"Bitwise AND and OR" Link "Bitwise AND and OR"}), so most of the time any non-zero number is taken to
be @{b}TRUE@{ub}.  It can sometimes be convenient to rely on this knowledge,
although most of the time it is preferable (and more readable) to use a
slightly more explicit form.  Also, these facts can cause a few subtle
problems as we shall see in the next section.


@EndNode

@Node "Precedence and grouping" "beginner.guide/Precedence and grouping"
@Prev "Logic and comparison"
@Toc "Expressions"

Precedence and grouping
-----------------------

   At school most of us are taught that multiplications must be done
before additions in a sum.  In E it's different--there is no operator
precedence.  This means that expressions like @{b}1+3*3@{ub} do not give the
results a mathematician might expect.  In fact, @{b}1+3*3@{ub} represents the
number 12 in E. This is because the addition, @{b}1+3@{ub}, is done before the
multiplication, since it occurs before the multiplication.  If the
multiplication were written before the addition it would be done first
(like we would normally expect).  Therefore, @{b}3*3+1@{ub} represents the number
10 in E and in school mathematics.

   To overcome this difference we can use parentheses to group the
expression.  If we'd written @{b}1+(3*3)@{ub} the result would be 10.  This is
because we've forced E to do the multiplication first.  Although this may
seem troublesome to begin with, it's actually a lot better than learning a
lot of rules for deciding which operator is done first (in C this can be a
real pain, and you usually end up writing the brackets in just to be
sure!).

   The logic examples above contained the expression:

       (2<1) AND (-1=0)

This expression was false.  If we'd left the parentheses out, E would have
seen it as:

       ((2<1) AND -1) = 0

Now the number -1 shouldn't really be used to represent a truth value with
@{b}AND@{ub}, but we do know that @{b}TRUE@{ub} is the number -1, so E will make sense of
this and the E compiler won't complain.  We will soon see how @{b}AND@{ub} and @{b}OR@{ub}
really work (see @{"Bitwise AND and OR" Link "Bitwise AND and OR"}), but for now we'll just work out what
E would calculate for this expression:

  1. Two is not less than one so @{b}2<1@{ub} can be replaced by @{b}FALSE@{ub}.

            (FALSE AND -1) = 0

  2.     @{b}TRUE@{ub} is -1 so we can replace -1 by @{b}TRUE@{ub}.

            (FALSE AND TRUE) = 0

  3.     @{b}FALSE AND TRUE@{ub} is @{b}FALSE@{ub}.

            (FALSE) = 0

  4.     @{b}FALSE@{ub} is really the number zero, so we can replace it with zero.

            0 = 0

  5. Zero is equal to zero, so the expression is @{b}TRUE@{ub}.

            TRUE

So E calculates the expression to be true.  But the original expression
(with parentheses) was false.  Bracketing is therefore very important!  It
is also very easy to do correctly.


@EndNode

@Node "Program Flow Control" "beginner.guide/Program Flow Control"
@Next "Summary"
@Prev "Variables and Expressions"
@Toc "Main"

Program Flow Control
********************

   A computer program often needs to repeatedly execute a series of
statements or execute different statements according to the result of some
decision.  For example, a program to print all the numbers between one and
a thousand would be very long and tedious to write if each print statement
had to be given individually--it would be much better to use a variable
and repeatedly print its value and increment it.  Also, things sometimes
go wrong and a program must decide whether to continue or print an error
message and stop--this part of a program is a typical example of a
conditional block.


 @{" Conditional Block " Link "Conditional Block"} 
 @{" Loops " Link "Loops"} 


@EndNode

@Node "Conditional Block" "beginner.guide/Conditional Block"
@Next "Loops"
@Toc "Program Flow Control"

Conditional Block
=================

   There are two kinds of conditional block: @{b}IF@{ub} and @{b}SELECT@{ub}.  Examples of
these blocks are given below as fragments of E code (i.e., the examples
are not complete E programs).

       IF x>0
         x:=x+1
         WriteF('Increment: x is now \d\n', x)
       ELSEIF x<0
         x:=x-1
         WriteF('Decrement: x is now \d\n', x)
       ELSE
         WriteF('Zero: x is 0\n')
       ENDIF

In the above @{b}IF@{ub} block, the first part checks if the value of @{b}x@{ub} is greater
than zero, and, if it is, @{b}x@{ub} is incremented and the new value is printed
(with a message saying it was incremented).  The program will then skip
the rest of the block, and will execute the statements which follow the
@{b}ENDIF@{ub}.  If, however, @{b}x@{ub} it is not greater than zero the @{b}ELSEIF@{ub} part is
checked, so if @{b}x@{ub} is less than zero it will be decremented and printed, and
the rest of the block is skipped.  If @{b}x@{ub} is not greater than zero and not
less than zero the statements in the @{b}ELSE@{ub} part are executed, so a message
saying @{b}x@{ub} is zero is printed.  The @{b}IF@{ub} conditional is described in more
detail below.


 @{" IF block " Link "IF block"} 
 @{" IF expression " Link "IF expression"} 

       SELECT x
         CASE 0
           WriteF('x is zero\n')
         CASE 10
           WriteF('x is ten\n')
         CASE -2
           WriteF('x is -2\n')
         DEFAULT
           WriteF('x is not zero, ten or -2\n')
       ENDSELECT

The @{b}SELECT@{ub} block is similar to the @{b}IF@{ub} block--it does different things
depending on the value of @{b}x@{ub}.  However, @{b}x@{ub} is only checked against specific
values, given in the series of @{b}CASE@{ub} statements.  If it is not any of these
values the @{b}DEFAULT@{ub} part is executed.

   There's also a variation on the @{b}SELECT@{ub} block (known as the @{b}SELECT..OF@{ub}
block) which matches ranges of values and is quite fast.  The two kinds of
@{b}SELECT@{ub} block are described in more detail below.


 @{" SELECT block " Link "SELECT block"} 
 @{" SELECT..OF block " Link "SELECT..OF block"} 


@EndNode

@Node "IF block" "beginner.guide/IF block"
@Next "IF expression"
@Toc "Conditional Block"

@{b}IF@{ub} block
--------

   The @{b}IF@{ub} block has the following form (the bits like @{fg shine}expression@{fg text} are
descriptions of the kinds of E code which is allowed at that point--they
are not proper E code):

       IF @{fg shine}expressionA@{fg text}
         @{fg shine}statementsA@{fg text}
       ELSEIF @{fg shine}expressionB@{fg text}
         @{fg shine}statementsB@{fg text}
       ELSE
         @{fg shine}statementsC@{fg text}
       ENDIF

This block means:

   @{b}*@{ub} If @{fg shine}expressionA@{fg text} is true (i.e., represents @{b}TRUE@{ub} or any non-zero
     number) the code denoted by @{fg shine}statementsA@{fg text} is executed.

   @{b}*@{ub} If @{fg shine}expressionA@{fg text} is false (i.e., represents @{b}FALSE@{ub} or zero) and
     @{fg shine}expressionB@{fg text} is true the @{fg shine}statementsB@{fg text} part is executed.

   @{b}*@{ub} If both @{fg shine}expressionA@{fg text} and @{fg shine}expressionB@{fg text} are false the @{fg shine}statementsC@{fg text}
     part is executed.

There does not need to be an @{b}ELSE@{ub} part but if one is present it must be
the last part (immediately before the @{b}ENDIF@{ub}).  Also, there can be any
number of @{b}ELSEIF@{ub} parts between the @{b}IF@{ub} and @{b}ELSE@{ub} parts.

   An alternative to this vertical form (where each part is on a separate
line) is the horizontal form:

       IF @{fg shine}expression@{fg text} THEN @{fg shine}statementA@{fg text} ELSE @{fg shine}statementB@{fg text}

This has the disadvantage of no @{b}ELSEIF@{ub} parts and having to cram everything
onto a single line.  Notice the presence of the @{b}THEN@{ub} keyword to separate the
@{fg shine}expression@{fg text} and @{fg shine}statement@{fg text}.  This horizontal form is closely related to
the @{b}IF@{ub} expression, which is described below (see @{"IF expression" Link "IF expression"}).

   To help make things clearer here are a number of E code fragments which
illustrate the allowable @{b}IF@{ub} blocks:

       IF x>0 THEN x:=x+1 ELSE x:=0
     
       IF x>0
         x:=x+1
       ELSE
         x:=0
       ENDIF
     
       IF x=0 THEN WriteF('x is zero\n')
     
       IF x=0
         WriteF('x is zero\n')
       ENDIF
     
       IF x<0
         Write('Negative x\n')
       ELSEIF x>2000
         Write('Too big x\n')
       ELSEIF (x=2000) OR (x=0)
         Write('Worrying x\n')
       ENDIF
     
       IF x>0
         IF x>2000
           WriteF('Big x\n')
         ELSE
           WriteF('OK x\n')
         ENDIF
       ELSE
         IF x<-800 THEN WriteF('Small x\n') ELSE Write('Negative OK x')
       ENDIF

In the last example there are @{fg shine}nested@{fg text} @{b}IF@{ub} blocks (i.e., an @{b}IF@{ub} block within
an @{b}IF@{ub} block).  There is no ambiguity in which @{b}ELSE@{ub} or @{b}ELSEIF@{ub} parts belong
to which @{b}IF@{ub} block because the beginning and end of the @{b}IF@{ub} blocks are
clearly marked.  For instance, the first @{b}ELSE@{ub} line can only be interpreted
as being part of the innermost @{b}IF@{ub} block.

   As a matter of style the conditions on the @{b}IF@{ub} and @{b}ELSEIF@{ub} parts should
not @{fg shine}overlap@{fg text} (i.e., at most one of the conditions should be true).  If
they do, however, the first one will take precedence.  Therefore, the
following two fragments of E code do the same thing:

       IF x>0
         WriteF('x is bigger than zero\n')
       ELSEIF x>200
         WriteF('x is bigger than 200\n')
       ELSE
         WriteF('x is too small\n')
       ENDIF
     
       IF x>0
         WriteF('x is bigger than zero\n')
       ELSE
         WriteF('x is too small\n')
       ENDIF

The @{b}ELSEIF@{ub} part of the first fragment checks whether @{b}x@{ub} is greater than 200.
But, if it is, the check in the @{b}IF@{ub} part would have been true (@{b}x@{ub} is
certainly greater than zero if it's greater than 200), and so only the
code in the @{b}IF@{ub} part is executed.  The whole @{b}IF@{ub} block behaves as if the
@{b}ELSEIF@{ub} was not there.


@EndNode

@Node "IF expression" "beginner.guide/IF expression"
@Next "SELECT block"
@Prev "IF block"
@Toc "Conditional Block"

@{b}IF@{ub} expression
-------------

   @{b}IF@{ub} is such a commonly used construction that there is also an @{b}IF@{ub}
expression.  The @{b}IF@{ub} block is a statement and it controls which lines of
code are executed, whereas the @{b}IF@{ub} expression is an expression and it
controls its own value.  For example, the following @{b}IF@{ub} block:

       IF x>0
         y:=x+1
       ELSE
         y:=0
       ENDIF

can be written more succinctly using an @{b}IF@{ub} expression:

       y:=(IF x>0 THEN x+1 ELSE 0)

The parentheses are unnecessary but they help to make the example more
readable.  Since the @{b}IF@{ub} block is just choosing between two assignments to
@{b}y@{ub} it isn't really the lines of code that are different (they are both
assignments), rather it is the values that are assigned to @{b}y@{ub} that are
different.  The @{b}IF@{ub} expression makes this similarity very clear.  It
chooses the @{i}value@{ui} to be assigned in just the same way that the @{b}IF@{ub} block
choose the @{i}assignment@{ui}.

   As you can see, @{b}IF@{ub} expressions are written like the horizontal form of
the @{b}IF@{ub} block.  However, there must be an @{b}ELSE@{ub} part and there can be no
@{b}ELSEIF@{ub} parts.  This means that the expression will always have a value,
and it isn't cluttered with lots of cases.

   Don't worry too much about @{b}IF@{ub} expressions, since there are only useful
in a handful of cases and can always be rewritten as a more wordy @{b}IF@{ub} block.
Having said that they are very elegant and a lot more readable than the
equivalent @{b}IF@{ub} block.


@EndNode

@Node "SELECT block" "beginner.guide/SELECT block"
@Next "SELECT..OF block"
@Prev "IF expression"
@Toc "Conditional Block"

@{b}SELECT@{ub} block
------------

   The @{b}SELECT@{ub} block has the following form:

       SELECT @{fg shine}variable@{fg text}
       CASE @{fg shine}expressionA@{fg text}
         @{fg shine}statementsA@{fg text}
       CASE @{fg shine}expressionB@{fg text}
         @{fg shine}statementsB@{fg text}
       DEFAULT
         @{fg shine}statementsC@{fg text}
       ENDSELECT

The value of the selection variable (denoted by @{fg shine}variable@{fg text} in the @{b}SELECT@{ub}
part) is compared with the value of the expression in each of the @{b}CASE@{ub}
parts in turn.  If there's a match, the statements in the (first) matching
@{b}CASE@{ub} part are executed.  There can be any number of @{b}CASE@{ub} parts between the
@{b}SELECT@{ub} and @{b}DEFAULT@{ub} parts.  If there is no match, the statements in the
@{b}DEFAULT@{ub} part are executed.  There does not need to be a @{b}DEFAULT@{ub} part but
if one is present it must be the last part (immediately before the
@{b}ENDSELECT@{ub}).

   It should be clear that @{b}SELECT@{ub} blocks can be rewritten as @{b}IF@{ub} blocks,
with the checks on the @{b}IF@{ub} and @{b}ELSEIF@{ub} parts being equality checks.  For
example, the following code fragments are equivalent:

       SELECT x
       CASE 22
         WriteF('x is 22\n')
       CASE (y+z)/2
         WriteF('x is (y+x)/2\n')
       DEFAULT
         WriteF('x isn't anything significant\n')
       ENDSELECT
     
       IF x=22
         WriteF('x is 22\n')
       ELSEIF x=(y+z)/2
         WriteF('x is (y+x)/2\n')
       ELSE
         WriteF('x isn't anything significant\n')
       ENDIF

Notice that the @{b}IF@{ub} and @{b}ELSEIF@{ub} parts come from the @{b}CASE@{ub} parts, the @{b}ELSE@{ub}
part comes from the @{b}DEFAULT@{ub} part, and the order of the parts is preserved.
The advantage of the @{b}SELECT@{ub} block is that it's much easier to see that the
value of @{b}x@{ub} is being tested all the time, and also we don't have to keep
writing @{b}x=@{ub} in the checks.


@EndNode

@Node "SELECT..OF block" "beginner.guide/SELECT..OF block"
@Prev "SELECT block"
@Toc "Conditional Block"

@{b}SELECT..OF@{ub} block
----------------

   The @{b}SELECT..OF@{ub} block is a bit more complicated than the normal @{b}SELECT@{ub}
block, but can be very useful.  It has the following form:

       SELECT @{fg shine}maxrange@{fg text} OF @{fg shine}expression@{fg text}
       CASE @{fg shine}constA@{fg text}
         @{fg shine}statementsA@{fg text}
       CASE @{fg shine}constB1@{fg text} TO @{fg shine}constB2@{fg text}
         @{fg shine}statementsB@{fg text}
       CASE @{fg shine}range1@{fg text}, @{fg shine}range2@{fg text}
         @{fg shine}statementsC@{fg text}
       DEFAULT
         @{fg shine}statementsD@{fg text}
       ENDSELECT

   The value to be matched is @{fg shine}expression@{fg text}, which can be any expression,
not just a variable like in the normal @{b}SELECT@{ub} block.  However, the
@{fg shine}maxrange@{fg text}, @{fg shine}constA@{fg text}, @{fg shine}constB1@{fg text} and @{fg shine}constB2@{fg text} must all be explicit numbers,
i.e., constants (see @{"Constants" Link "Constants"}).  @{fg shine}maxrange@{fg text} must be a positive constant
and the other constants must be between zero and @{fg shine}maxrange@{fg text} (including
zero but excluding @{fg shine}maxrange@{fg text}).

   The @{b}CASE@{ub} values to be matched are specified using @{fg shine}ranges@{fg text}.  A simple
range is a single constant (the first @{b}CASE@{ub} above).  The more general range
is shown in the second @{b}CASE@{ub}, using the @{b}TO@{ub} keyword (@{fg shine}constB2@{fg text} must be
greater than @{fg shine}constB1@{fg text}).  A general @{b}CASE@{ub} in the @{b}SELECT..OF@{ub} block can
specify a number of possible ranges to match against by separating each
range with a comma, as in the third @{b}CASE@{ub} above.  For example, the
following @{b}CASE@{ub} lines are equivalent and can be used to match any number
from one to five (inclusive):

       CASE 1 TO 5
     
       CASE 1, 2, 3, 4, 5
     
       CASE 1 TO 3, 3 TO 5
     
       CASE 1, 2 TO 3, 4, 5
     
       CASE 1, 5, 2, 4, 3
     
       CASE 2 TO 3, 5, 1, 4

   If the value of the @{fg shine}expression@{fg text} is less than zero, greater than or
equal to @{fg shine}maxrange@{fg text}, or it does not match any of the constants in the @{b}CASE@{ub}
ranges, then the statements in the @{b}DEFAULT@{ub} part are executed.  Otherwise
the statements in the first matching @{b}CASE@{ub} part are executed.  As in the
normal @{b}SELECT@{ub} block, there does not need to be a @{b}DEFAULT@{ub} part.

   The following @{b}SELECT..OF@{ub} block prints the (numeric) day of the month
nicely:

       SELECT 32 OF day
       CASE 1, 21, 31
         WriteF('The \dst day of the month\n', day)
       CASE 2, 22
         WriteF('The \dnd day of the month\n', day)
       CASE 3, 23
         WriteF('The \drd day of the month\n', day)
       CASE 4 TO 20, 24 TO 30
         WriteF('The \dth day of the month\n', day)
       DEFAULT
         WriteF('Error: invalid day=\d\n', day)
       ENDSELECT

The @{fg shine}maxrange@{fg text} for this block is 32, since 31 is the maximum of the values
used in the @{b}CASE@{ub} parts.  If the value of @{b}day@{ub} was 100, for instance, then
the statements in the @{b}DEFAULT@{ub} part would be executed, signalling an
invalid day.

   This example can be rewritten as an @{b}IF@{ub} block:

       IF (day=1) OR (day=21) OR (day=31)
         WriteF('The \dst day of the month\n', day)
       ELSEIF (day=2) OR (day=22)
         WriteF('The \dnd day of the month\n', day)
       ELSEIF (day=3) OR (day=23)
         WriteF('The \drd day of the month\n', day)
       ELSEIF ((4<=day) AND (day<=20))  OR  ((24<=day) AND (day<=30))
         WriteF('The \dth day of the month\n', day)
       ELSE
         WriteF('Error: invalid day=\d\n', day)
       ENDIF

The comma separating two ranges in the @{b}CASE@{ub} part has been replaced by an
@{b}OR@{ub} of two comparison expressions, and the @{b}TO@{ub} range has been replaced
by an @{b}AND@{ub} of two comparisons.  (It is worth noticing the careful
bracketing of the resulting expressions.)

   Clearly, the @{b}SELECT..OF@{ub} block is much more readable than the equivalent
@{b}IF@{ub} block.  It is also a lot faster, mainly because none of the comparisons
present in @{b}IF@{ub} block have to be done in the @{b}SELECT..OF@{ub} version.  Instead
the value to be matched is used to immediately locate the correct @{b}CASE@{ub}
part.  However, it's not all good news: the @{fg shine}maxrange@{fg text} value directly
affects the size of compiled executable, so it is recommended that
@{b}SELECT..OF@{ub} blocks be used only with small @{fg shine}maxrange@{fg text} values.  See the
`Reference Manual' for more details.


@EndNode

@Node "Loops" "beginner.guide/Loops"
@Prev "Conditional Block"
@Toc "Program Flow Control"

Loops
=====

   Loops are all about making a program execute a series of statements
over and over again.  Probably the simplest loop to understand is the @{b}FOR@{ub}
loop.  There are other kinds of loops, but they are easier to understand
once we know how to use a @{b}FOR@{ub} loop.


 @{" FOR loop " Link "FOR loop"} 
 @{" WHILE loop " Link "WHILE loop"} 
 @{" REPEAT..UNTIL loop " Link "REPEAT..UNTIL loop"} 


@EndNode

@Node "FOR loop" "beginner.guide/FOR loop"
@Next "WHILE loop"
@Toc "Loops"

@{b}FOR@{ub} loop
--------

   If you want to write a program to print the numbers one to 100 you can
either type each number and wear out your fingers, or you can use a single
variable and a small @{b}FOR@{ub} loop.  Try compiling this E program (the space
after the @{b}\d@{ub} in the string is needed to separate the printed numbers):

     PROC main()
       DEF x
       FOR x:=1 TO 100
         WriteF('\d ', x)
       ENDFOR
       WriteF('\n')
     ENDPROC

When you run this you'll get all the numbers from one to 100 printed, just
like we wanted.  It works by using the (local) variable @{b}x@{ub} to hold the
number to be printed.  The @{b}FOR@{ub} loop starts off by setting the value of @{b}x@{ub}
to one (the bit that looks like an assignment).  Then the statements
between the @{b}FOR@{ub} and @{b}ENDFOR@{ub} lines are executed (so the value of @{b}x@{ub} gets
printed).  When the program reaches the @{b}ENDFOR@{ub} it increments @{b}x@{ub} and checks
to see if it is bigger than 100 (the limit we set with the @{b}TO@{ub} part).  If
it is, the loop is finished and the statements after the @{b}ENDFOR@{ub} are
executed.  If, however, it wasn't bigger than 100, the statements between
the @{b}FOR@{ub} and @{b}ENDFOR@{ub} lines are executed all over again, and this time @{b}x@{ub} is
one bigger since it has been incremented.  In fact, this program does
exactly the same as the following program (the @{b}...@{ub} is not E code--it
stands for the 97 other @{b}WriteF@{ub} statements):

     PROC main()
       WriteF('\d ', 1)
       WriteF('\d ', 2)
       ...
       WriteF('\d ', 100)
       WriteF('\n')
     ENDPROC

   The general form of the @{b}FOR@{ub} loop is as follows:

       FOR @{fg shine}var@{fg text} := @{fg shine}expressionA@{fg text} TO @{fg shine}expressionB@{fg text} STEP @{fg shine}number@{fg text}
         @{fg shine}statements@{fg text}
       ENDFOR

The @{fg shine}var@{fg text} bit stands for the loop variable (in the example above this was
@{b}x@{ub}).  The @{fg shine}expressionA@{fg text} bit gives the start value for the loop variable
and the @{fg shine}expressionB@{fg text} bit gives the last allowable value for it.  The @{b}STEP@{ub}
part allows you to specify the value (given by @{fg shine}number@{fg text}) which is added to
the loop variable on each loop.  Unlike the values given for the start and
end (which can be arbitrary expressions), the @{b}STEP@{ub} value must be a
constant (see @{"Constants" Link "Constants"}).  The @{b}STEP@{ub} value defaults to one if the @{b}STEP@{ub} part
is omitted (as in our example).  Negative @{b}STEP@{ub} values are allowed, but in
this case the check used at the end of each loop is whether the loop
variable is @{i}less than@{ui} the value in the @{b}TO@{ub} part.  Zero is not allowed as
the @{b}STEP@{ub} value.

   As with the @{b}IF@{ub} block there is a horizontal form of a @{b}FOR@{ub} loop:

       FOR @{fg shine}var@{fg text} := @{fg shine}expA@{fg text} TO @{fg shine}expB@{fg text} STEP @{fg shine}expC@{fg text} DO @{fg shine}statement@{fg text}


@EndNode

@Node "WHILE loop" "beginner.guide/WHILE loop"
@Next "REPEAT..UNTIL loop"
@Prev "FOR loop"
@Toc "Loops"

@{b}WHILE@{ub} loop
----------

   The @{b}FOR@{ub} loop used a loop variable and checked whether that variable had
gone past its limit.  A @{b}WHILE@{ub} loop allows you to specify your own loop
check.  For instance, this program does the same as the program in the
previous section:

     PROC main()
       DEF x
       x:=1
       WHILE x<=100
         WriteF('\d ', x)
         x:=x+1
       ENDWHILE
       WriteF('\n')
     ENDPROC

We've replaced the @{b}FOR@{ub} loop with an initialisation of @{b}x@{ub} and a @{b}WHILE@{ub} loop
with an extra statement to increment @{b}x@{ub}.  We can now see the inner workings
of the @{b}FOR@{ub} loop and, in fact, this is exactly how the @{b}FOR@{ub} loop works.

   It is important to know that our check, @{b}x<=100@{ub}, is done before the loop
statements are executed.  This means that the loop statements might not
even be executed once.  For instance, if we'd made the check @{b}x>=100@{ub} it
would be false at the beginning of the loop (since @{b}x@{ub} is initialised to one
in the assignment before the loop).  Therefore, the loop would have
terminated immediately and execution would pass straight to the statements
after the @{b}ENDWHILE@{ub}.

   Here's a more complicated example:

     PROC main()
       DEF x,y
       x:=1
       y:=2
       WHILE (x<10) AND (y<10)
         WriteF('x is \d and y is \d\n', x, y)
         x:=x+2
         y:=y+2
       ENDWHILE
     ENDPROC

We've used two (local) variables this time.  As soon as one of them is ten
or more the loop is terminated.  A bit of inspection of the code reveals
that @{b}x@{ub} is initialised to one, and keeps having two added to it.  It will,
therefore, always be an odd number.  Similarly, @{b}y@{ub} will always be even.
The @{b}WHILE@{ub} check shows that it won't print any numbers which are greater
than or equal to ten.  From this and the fact that @{b}x@{ub} starts at one and @{b}y@{ub}
at two we can decide that the last pair of numbers will be seven and eight.
Run the program to confirm this.  It should produce the following output:

     x is 1 and y is 2
     x is 3 and y is 4
     x is 5 and y is 6
     x is 7 and y is 8

   Like the @{b}FOR@{ub} loop, there is a horizontal form of the @{b}WHILE@{ub} loop:

       WHILE @{fg shine}expression@{fg text} DO @{fg shine}statement@{fg text}

   Loop termination is always a big problem.  @{b}FOR@{ub} loops are guaranteed to
eventually reach their limit (if you don't mess with the loop variable,
that is).  However, @{b}WHILE@{ub} loops (and all other loops) may go on forever
and never terminate.  For example, if the loop check were @{b}1<2@{ub} it would
always be true and nothing the loop could do would prevent it being true!
You must therefore take care that you make sure your loops terminate in
some way if you want to program to finish.  There is a sneaky way of
terminating loops using the @{b}JUMP@{ub} statement, but we'll ignore that for now.


@EndNode

@Node "REPEAT..UNTIL loop" "beginner.guide/REPEAT..UNTIL loop"
@Prev "WHILE loop"
@Toc "Loops"

@{b}REPEAT..UNTIL@{ub} loop
------------------

   A @{b}REPEAT..UNTIL@{ub} loop is very similar to a @{b}WHILE@{ub} loop.  The only
difference is where you specify the loop check, and when and how the check
is performed.  To illustrate this, here's the program from the previous
two sections rewritten using a @{b}REPEAT..UNTIL@{ub} loop (try to spot the subtle
differences):

     PROC main()
       DEF x
       x:=1
       REPEAT
         WriteF('\d ', x)
         x:=x+1
       UNTIL x>100
       WriteF('\n')
     ENDPROC

Just as in the @{b}WHILE@{ub} loop version we've got an initialisation of @{b}x@{ub} and an
extra statement in the loop to increment @{b}x@{ub}.  However, this time the loop
check is specified at the end of the loop (in the @{b}UNTIL@{ub} part), and the
check is only performed at the end of each loop.  This difference means
that the code in a @{b}REPEAT..UNTIL@{ub} loop will be executed at least once,
whereas the code in a @{b}WHILE@{ub} loop may never be executed.  Also, the logical
sense of the check follows the English: a @{b}REPEAT..UNTIL@{ub} loop executes
@{i}until@{ui} the check is true, whereas the @{b}WHILE@{ub} loop executes @{i}while@{ui} the
check is true.  Therefore, the @{b}REPEAT..UNTIL@{ub} loop executes while the check
is false!  This may seem confusing at first, but just remember to read the
code as if it were English and you'll get the correct interpretation.


@EndNode

@Node "Summary" "beginner.guide/Summary"
@Next "Format and Layout"
@Prev "Program Flow Control"
@Toc "Main"

Summary
*******

   This is the end of Part One, which was hopefully enough to get you
started.  If you've grasped the main concepts you are good position to
attack Part Two, which covers the E language in more detail.

   This is probably a good time to look at the different parts of one of
the examples from the previous sections, since we've now used quite a bit
of E. The following examination uses the @{b}WHILE@{ub} loop example.  Just to make
things easier to follow, each line has been numbered (don't try to compile
it with the line numbers on!).

      1.  PROC main()
      2.    DEF x,y
      3.    x:=1
      4.    y:=2
      5.    WHILE (x<10) AND (y<10)
      6.      WriteF('x is \d and y is \d\n', x, y)
      7.      x:=x+2
      8.      y:=y+2
      9.    ENDWHILE
     10.  ENDPROC

Hopefully, you should be able to recognise all the features listed in the
table below.  If you don't then you might need to go back over the
previous chapters, or find a much better programming guide than this!

     @{i}Line(s)@{ui}  @{i}Observation@{ui}
     ---------------------------------------------------------
      1-10    The procedure definition.
     
         1    The declaration of the procedure @{b}main@{ub}, with no
              parameters.
     
         2    The declaration of local variables @{b}x@{ub} and @{b}y@{ub}.
     
      3, 4    Initialisation of @{b}x@{ub} and @{b}y@{ub} using assignment
              statements.
     
       5-9    The @{b}WHILE@{ub} loop.
     
         5    The loop check for the @{b}WHILE@{ub} loop using the
              logical operator @{b}AND@{ub}, the comparison operator
              @{b}<@{ub}, and parentheses to group the expression.
     
         6    The call to the (built-in) procedure @{b}WriteF@{ub}
              using parameters.  Notice the string, the place
              holders for numbers, @{b}\d@{ub}, and the linefeed,
              @{b}\n@{ub}.
     
      7, 8    Assignments to @{b}x@{ub} and @{b}y@{ub}, adding two to
              their values.
     
         9    The marker for the end of the @{b}WHILE@{ub} loop.
     
        10    The marker for the end of the procedure.


@EndNode

@Node "Format and Layout" "beginner.guide/Format and Layout"
@Next "Procedures and Functions"
@Prev "Summary"
@Toc "Main"

Format and Layout
*****************

   In this chapter we'll look at the rules which govern the format and
layout of E code.  In the previous Part we saw examples of E code that
were quite nicely indented and the structure of the program was easily
visible.  This was just a convention and the E language does not constrain
you to write code in this way.  However, there are certain rules that must
be followed.  (This chapter refers to some concepts and parts of the E
language which were not covered in Part One.  Don't let this put you
off--those things will be dealt with in later chapters, and it's maybe a
good idea to read this chapter again when they have been.)


 @{" Identifiers " Link "Identifiers"} 
 @{" Statements " Link "Statements"} 
 @{" Spacing and Separators " Link "Spacing and Separators"} 
 @{" Comments " Link "Comments"} 


@EndNode

@Node "Identifiers" "beginner.guide/Identifiers"
@Next "Statements"
@Toc "Format and Layout"

Identifiers
===========

   An @{fg shine}identifier@{fg text} is a word which the compiler must interpret rather than
treating literally.  For instance, a variable is an identifier, as is a
keyword (e.g., @{b}IF@{ub}), but anything in a string is not (e.g., @{b}fred@{ub} in @{b}'fred
and wilma'@{ub} is not an identifier).  Identifiers can be made up of upper- or
lower-case letters, numbers and underscores (the @{b}_@{ub} character).  There are
only two constraints:

  1. The first character cannot be a number (this would cause confusion
     with numeric constants).

  2. The case of the first few characters of identifiers is significant.

For keywords (e.g., @{b}ENDPROC@{ub}), constants (e.g., @{b}TRUE@{ub}) and assembly
mnemonics (e.g., @{b}MOVE.L@{ub}) the first two characters must both be uppercase.
For E built-in or Amiga system procedures/functions the first character
must be uppercase and the second must be lowercase.  For all other
identifiers (i.e., local, global and procedure parameter variables, object
names and element names, procedure names and code labels) the first
character must be lowercase.

   Apart from these constraints you are free to write identifiers how you
like, although it's arguably more tasteful to use all lowercase for
variables and all uppercase for keywords and constants.


@EndNode

@Node "Statements" "beginner.guide/Statements"
@Next "Spacing and Separators"
@Prev "Identifiers"
@Toc "Format and Layout"

Statements
==========

   A @{fg shine}statement@{fg text} is normally a single line of an instruction to the
computer.  Each statement normally occupies a single line.  If a procedure
is thought of as a paragraph then a statement is a sentence.  Variables,
expressions and keywords are the words which make up the sentence.

   So far in our examples we have met only two kinds of statement: the
single line statement and the multi-line statement.  The assignments we
have seen were single line statements, and the vertical form of the @{b}IF@{ub}
block is a multi-line statement.  The horizontal form of the @{b}IF@{ub} block was
actually the single line statement form of the @{b}IF@{ub} block.  Notice that
statements can be built up from other statements, as is the case for @{b}IF@{ub}
blocks.  The code parts between the @{b}IF@{ub}, @{b}ELSEIF@{ub}, @{b}ELSE@{ub} and @{b}ENDIF@{ub} lines are
sequences of statements.

   Single line statements can often be very short, and you may be able to
fit several of them onto an single line without the line getting too long.
To do this in E you use a semi-colon (the @{b};@{ub} character) to separate each
statement on the line.  For example, the following code fragments are
equivalent:

       fred(y,z)
       y:=x
       x:=z+1
     
       fred(y,z); y:=x; x:=z+1

   On the other hand you may want to split a long statement over several
lines.  This is a bit more tricky because the compiler needs to see that
you haven't finished the statement when it gets to the end of a line.
Therefore you can only break a statement at certain places.  The most
common place is after a comma that is part of the statement (like in a
procedure call with more than one parameter), but you can also split a
line after binary operators and anywhere between opening and closing
brackets.  The following examples are rather silly but show some allowable
line breaking places.

        fred(a, b, c,
             d, e, f)   /* After a comma */
     
        x:=x+
           y+
           z            /* After a binary operator */
     
        x:=(1+2
            +3)         /* Between open...close brackets */
     
        list:= [ 1,2,
                 [3,4],
                ]       /* Between open...close brackets */

The simple rule is this: if a complete line can be interpreted as a
statement then it will be, otherwise it will be interpreted as part of a
statement which continues on the following lines.

   Strings may also get a bit long.  You can split them over several lines
by breaking them into several separate strings and using @{b}+@{ub} between them.
If a line ends with a @{b}+@{ub} and the previous thing on the line was a string
then the E compiler takes the next string to be a continuation.  The
following calls to @{b}WriteF@{ub} print the same thing:

       WriteF('This long string can be broken over several lines.\n')
     
       WriteF('This long string ' +
              'can be broken over several lines.\n')
     
       WriteF('This long' +
              ' string can be ' +
              'broken over several ' +
              'lines.\n')


@EndNode

@Node "Spacing and Separators" "beginner.guide/Spacing and Separators"
@Next "Comments"
@Prev "Statements"
@Toc "Format and Layout"

Spacing and Separators
======================

   The examples we've seen so far used a rigid indentation convention
which was intended to illuminate the structure of the program.  This was
just a convention, and the E language places no constraints on the amount
of @{fg shine}whitespace@{fg text} (spaces, tabs and linefeeds) you place between statements.
However, within statements you must supply enough spacing to make the
statement readable.  This generally means that you must put whitespace
between adjacent identifiers which start or end with a letter, number or
underscore (so that the compiler does not think it's one big identifier!).
In practice this means you should put a space after a keyword if it might
run into a variable or procedure name.  Most other times (like in
expressions) identifiers are separated by non-identifier characters (a
comma, parenthesis or other symbol).


@EndNode

@Node "Comments" "beginner.guide/Comments"
@Prev "Spacing and Separators"
@Toc "Format and Layout"

Comments
========

   A @{fg shine}comment@{fg text} is something that the E compiler ignores and is only there
to help the reader.  Remember that one day in the future you may be the
reader, and it may be quite hard to decipher your own code without a few
decent comments!  Comments are therefore pretty important.

   You can write comments anywhere you can write whitespace that isn't
part of a string.  There are two kinds of comment: one uses @{b}/*@{ub} to mark the
start of the comment text and @{b}*/@{ub} to mark the end, and the other uses @{b}->@{ub} to
mark the start, with the comment text continuing to the end of the line.
You must be careful not to write @{b}/*@{ub}, @{b}*/@{ub} or @{b}->@{ub} as part of the comment text,
unless part of a nested comment.  In practice a comment is best put on a
line by itself or after the end of the code on a line.

        /* This line is a comment */
        x:=1  /* This line contains an assignment then a comment */
     /* y:=2  /* This whole line is a comment with a nested comment */*/
     
        x:=1  -> Assignment then a comment
     -> y:=2  /* A nested comment comment */


@EndNode

@Node "Procedures and Functions" "beginner.guide/Procedures and Functions"
@Next "Constants"
@Prev "Format and Layout"
@Toc "Main"

Procedures and Functions
************************

   A @{fg shine}function@{fg text} is a procedure which returns a value.  This value can be
any expression so it may depend on the parameters with which the function
was called.  For instance, the addition operator @{b}+@{ub} can be thought of as a
function which returns the sum of its two parameters.


 @{" Functions " Link "Functions"} 
 @{" One-Line Functions " Link "One-Line Functions"} 
 @{" Default Arguments " Link "Default Arguments"} 
 @{" Multiple Return Values " Link "Multiple Return Values"} 


@EndNode

@Node "Functions" "beginner.guide/Functions"
@Next "One-Line Functions"
@Toc "Procedures and Functions"

Functions
=========

   We can define our own addition function, @{b}add@{ub}, in a very similar way to
the definition of a procedure.  (The only difference is that a function
explicitly returns a value.)

     PROC main()
       DEF sum
       sum:=12+79
       WriteF('Using +, sum is \d\n', sum)
       sum:=add(12,79)
       WriteF('Using add, sum is \d\n', sum)
     ENDPROC
     
     PROC add(x, y)
       DEF s
       s:=x+y
     ENDPROC s

This should generate the following output:

     Using +, sum is 91
     Using add, sum is 91

In the procedure @{b}add@{ub} the value @{b}s@{ub} is returned using the @{b}ENDPROC@{ub} label.  The
value returned from @{b}add@{ub} can be used in expressions, just like any other
value.  You do this by writing the procedure call where you want the value
to be.  In the above example we wanted the value to be assigned to @{b}sum@{ub} so
we wrote the call to @{b}add@{ub} on the right-hand side of the assignment.  Notice
the similarities between the uses of @{b}+@{ub} and @{b}add@{ub}.  In general, @{b}add(a,b)@{ub} can
be used in exactly the same places that @{b}a+b@{ub} can (more precisely, it can be
used anywhere @{b}(a+b)@{ub} can be used).

   The @{b}RETURN@{ub} keyword can also be used to return values from a procedure.
If the @{b}ENDPROC@{ub} method is used then the value is returned when the
procedure reaches the end of its code.  However, if the @{b}RETURN@{ub} method is
used the value is returned immediately at that point and no more of the
procedure's code is executed.  Here's the same example using @{b}RETURN@{ub}:

     PROC add(x, y)
       DEF s
       s:=x+y
       RETURN s
     ENDPROC

The only difference is that you can write @{b}RETURN@{ub} anywhere in the code part
of a procedure and it finishes the execution of the procedure at that
point (rather than execution finishing when it reaches the end of the
code).  In fact, you can use @{b}RETURN@{ub} in the @{b}main@{ub} procedure to prematurely
finish the execution of a program.

   Here's a slightly more complicated use of @{b}RETURN@{ub}:

     PROC limitedadd(x,y)
       IF x>10000
         RETURN 10000
       ELSEIF x<-10000
         RETURN -10000
       ELSE
         RETURN x+y
       ENDIF
       /* The following code is redundant */
       x:=1
       IF x=1 THEN RETURN 9999 ELSE RETURN -9999
     ENDPROC

This function checks to see if @{b}x@{ub} is greater than 10,000 or less than
-10,000, and if it is a limited value is returned (which is generally not
the correct sum!).  If @{b}x@{ub} is between -10,000 and 10,000 the correct answer
is returned.  The lines after the first @{b}IF@{ub} block will never get executed
because execution will have finished at one of the @{b}RETURN@{ub} lines.  Those
lines are therefore just a waste of compiler time and can safely be
omitted (as the comment suggests).

   If no value is given with the @{b}ENDPROC@{ub} or @{b}RETURN@{ub} keyword then zero is
returned.  Therefore, all procedures are actually functions (and the terms
@{fg shine}procedure@{fg text} and @{fg shine}function@{fg text} will tend to be used interchangeably).  So, what
happens to the value when you write a procedure call on a line by itself,
not in an expression?  Well, as we will see, the value is simply discarded
(see @{"Turning an Expression into a Statement" Link "Turning an Expression into a Statement"}).  This is what happened in
the previous examples when we called the procedures @{b}fred@{ub} and @{b}WriteF@{ub}.


@EndNode

@Node "One-Line Functions" "beginner.guide/One-Line Functions"
@Next "Default Arguments"
@Prev "Functions"
@Toc "Procedures and Functions"

One-Line Functions
==================

   Just as the @{b}IF@{ub} block and @{b}FOR@{ub} loop have horizontal, single line forms,
so does a procedure definition.  The general form is:

     PROC @{fg shine}name@{fg text} (@{fg shine}arg1@{fg text}, @{fg shine}arg2@{fg text}, ...) IS @{fg shine}expression@{fg text}

Alternatively, the @{b}RETURN@{ub} keyword can be used:

     PROC @{fg shine}name@{fg text} (@{fg shine}arg1@{fg text}, @{fg shine}arg2@{fg text}, ...) RETURN @{fg shine}expression@{fg text}

At first sight this might seem pretty unusable, but it is useful for very
simple functions and our @{b}add@{ub} function in the previous section is a good
example.  If you look closely at the original definition you'll see that
the local variable @{b}s@{ub} wasn't really needed.  Here's the one-line definition
of @{b}add@{ub}:

     PROC add(x,y) IS x+y


@EndNode

@Node "Default Arguments" "beginner.guide/Default Arguments"
@Next "Multiple Return Values"
@Prev "One-Line Functions"
@Toc "Procedures and Functions"

Default Arguments
=================

   Sometimes a procedure (or function) will quite often be called with a
particular (constant) value for one of its parameters, and it might be
nice if you didn't have to fill this value in all the time.  Luckily, E
allows you to define @{fg shine}default@{fg text} values for a procedure's parameters when
you define the procedure.  You can then just leave out that parameter when
you call the procedure and it will default to the value you defined for it.
Here's a simple example:

     PROC play(track=1)
       WriteF('Starting to play track \d\n', track)
       /* Rest of the code... */
     ENDPROC
     
     PROC main()
       play(1)  -> Start playing from track 1
       play(6)  -> Start playing from track 6
       play()   -> Start playing from track 1
     ENDPROC

This is an outline of a program to control something like a CD player.
The @{b}play@{ub} procedure has one parameter, @{b}track@{ub}, which represents the first
track that should be played.  Often, though, you just tell the CD player
to play, and don't specify a particular track.  In this case, play starts
from the first track.  This is exactly what happens in the example above:
the @{b}track@{ub} parameter has a default value of 1 defined for it (the @{b}=1@{ub} in the
definition of the @{b}play@{ub} procedure), and the third call to @{b}play@{ub} in @{b}main@{ub} does
not specify a value for @{b}track@{ub}, so the default value is used.

   There are two constraints on the use of default arguments:

  1. Any number of the parameters of a procedure may have default values
     defined for them, although they may only be the right-most parameters.
     This means that for a three parameter procedure, the second parameter
     can have a default value only if the last parameter does as well, and
     the first can have one only if both the others do.  This should not
     be a big problem because you can always reorder the parameters in the
     procedure definition.

     The following examples show legal definitions of procedures with
     default arguments:

          PROC fred(x, y, z) IS x+y+z         -> No defaults
          
          PROC fred(x, y, z=1) IS x+y+z       -> z defaults to 1
          
          PROC fred(x, y=23, z=1) IS x+y+z    -> y and z have defaults
          
          PROC fred(x=9, y=23, z=1) IS x+y+z  -> All have defaults

     On the other hand, these definitions are all illegal:

          PROC fred(x, y=23, z) IS x+y+z   -> Illegal: no z default
          
          PROC fred(x=9, y, z=1) IS x+y+z  -> Illegal: no y default

  2. When you call a procedure which has default arguments you can only
     leave out the right-most parameters.  This means that for a three
     parameter procedure with all three parameters having default values,
     you can leave out the second parameter in a call to this procedure
     only if you also leave out the third parameter.  The first parameter
     may be left out only if both the others are, too.

     The following example shows which parameters are considered defaults:

          PROC fred(x, y=23, z=1)
            WriteF('x is \d, y is \d, z is \d\n', x, y, z)
          ENDPROC
          
          PROC main()
            fred(2, 3, 4) -> No defaults used
            fred(2, 3)    -> z defaults to 1
            fred(2)       -> y and z default
            fred()        -> Illegal: x has no default
          ENDPROC

     In this example, you cannot leave out the @{b}y@{ub} parameter in a call to
     @{b}fred@{ub} without leaving out the @{b}z@{ub} parameter as well.  To make @{b}y@{ub} have its
     default value and @{b}z@{ub} some value other than its default you need to
     supply the @{b}y@{ub} value explicitly in the call:

            fred(2, 23, 9) -> Need to supply 23 for y

These constraints are necessary in order to make procedure calls
unambiguous.  Consider a three-parameter procedure with default values for
two of the parameters.  If it is called with only two parameters then,
without these constraints, it would not be clear which two parameters had
been supplied and which had not.  If, however, the procedure were defined
and called according to these constraints, then it must be the third
parameter that needs to be defaulted (and the two parameters with default
values must be the last two).


@EndNode

@Node "Multiple Return Values" "beginner.guide/Multiple Return Values"
@Prev "Default Arguments"
@Toc "Procedures and Functions"

Multiple Return Values
======================

   So far we've only seen functions which return only one value, since
this is something common to most programming languages.  However, E allows
you to return up to three values from a function.  To do this you list the
values separated by commas after the @{b}ENDPROC@{ub}, @{b}RETURN@{ub} or @{b}IS@{ub} keyword, where
you would normally have specified only one value.  A good example is a
function which manipulates a screen coordinate, which is a pair of values:
the x- and y-coordinates.

     PROC movediag(x, y) IS x+8, y+4

All this function does is add 8 to the x-coordinate and 4 to the
y-coordinate.  To get to the return values other than the first one you
must use a multiple-assignment statement:

     PROC main()
       DEF a, b
       a, b:=movediag(10, 3)
       /* Now a should be 10+8, and b should be 3+4 */
       WriteF('a is \d, b is \d\n', a, b)
     ENDPROC

@{b}a@{ub} is assigned the first return value and @{b}b@{ub} is assigned the second.  You
don't need to use all the return values from a function, so the assignment
in the example above could have assigned only to @{b}a@{ub} (in which case it would
not be a multiple-assignment anymore).  A multiple-assignment makes sense
only if the right-hand side is a function call, so don't expect things
like the following example to set @{b}b@{ub} properly:

       a,b:=6+movediag(10,3)  -> No obvious value for b

   If you use a function with more than one return value in any other
expression (i.e., something which is not the right-hand side of an
assignment), then only the first return value is used.  For this reason
the return values of a function have special names: the first return value
is called the @{fg shine}regular@{fg text} value of the function, and the other values are
the @{fg shine}optional@{fg text} values.

     PROC main()
       DEF a, b
       /* The next two lines ignore the second return value */
       a:=movediag(10, 3)
       WriteF('x-coord of movediag(21, 4) is \d\n', movediag(21,4))
     ENDPROC


@EndNode

@Node "Constants" "beginner.guide/Constants"
@Next "Types"
@Prev "Procedures and Functions"
@Toc "Main"

Constants
*********

   A @{fg shine}constant@{fg text} is a value that does not change.  A (literal) number like
121 is a good example of a constant--its value is always 121.  We've
already met another kind of constant: string constants (see @{"Strings" Link "Strings"}).  As
you can doubtless tell, constants are pretty important things.


 @{" Numeric Constants " Link "Numeric Constants"} 
 @{" String Constants Special Character Sequences " Link "String Constants Special Character Sequences"} 
 @{" Named Constants " Link "Named Constants"} 
 @{" Enumerations " Link "Enumerations"} 
 @{" Sets " Link "Sets"} 


@EndNode

@Node "Numeric Constants" "beginner.guide/Numeric Constants"
@Next "String Constants Special Character Sequences"
@Toc "Constants"

Numeric Constants
=================

   We've met a lot of numbers in the previous examples.  Technically
speaking, these were numeric constants (constant because they don't change
value like a variable might).  They were all decimal numbers, but you can
use hexadecimal and binary numbers as well.  There's also a way of
specifying a number using characters.  To specify a hexadecimal number you
use a @{b}$@{ub} before the digits (and after the optional minus sign @{b}-@{ub} to
represent a negative value).  To specify a binary number you use a @{b}%@{ub}
instead.

   Specifying numbers using characters is more complicated, because the
base of this system is 256 (the base of decimal is ten, that of
hexadecimal is 16 and that of binary is two).  The digits are enclosed in
double-quotes (the " character), and there can be at most four digits.
Each digit is a character representing its ASCII value.  Therefore, the
character @{b}A@{ub} represents 65 and the character @{b}0@{ub} (zero) represents 48.  This
upshot of this is that character @{b}A@{ub} has ASCII value @{b}"A"@{ub} in E, and @{b}"0z"@{ub}
represents ("0" * 256) + "z" = (48 * 256) + 122 = 12,410.  However, you
probably don't need to worry about anything other than the single
character case, which gives you the ASCII value of the character.

   The following table shows the decimal value of several numeric
constants.  Notice that you can use upper- or lower-case letters for the
hexadecimal constants.  Obviously the case of characters is significant
for character numbers.

      @{i}Number@{ui}  @{i}Decimal value@{ui}
     ----------------------
         21          21
       -143        -143
        $1a          26
       -$B1        -177
      %1110          14
     -%1010         -10
        "z"         122
       "Je"      19,045
       -"A"         -65


@EndNode

@Node "String Constants Special Character Sequences" "beginner.guide/String Constants Special Character Sequences"
@Next "Named Constants"
@Prev "Numeric Constants"
@Toc "Constants"

String Constants: Special Character Sequences
=============================================

   We have seen that in a string the character sequence @{b}\n@{ub} means a
linefeed (see @{"Strings" Link "Strings"}).  There are several other similar such special
character sequences which represent useful characters that can't be typed
in a string.  The following table shows all these sequences.  Note that
there are some other similar sequences which are used to control
formatting with built-in procedures like @{b}WriteF@{ub}.  These are listed where
@{b}WriteF@{ub} and similar procedures are described (see
@{"Input and output functions" Link "Input and output functions"}).

     @{i}Sequence@{ui}          @{i}Meaning@{ui}
     --------------------------------------
        \0     A null (ASCII zero)
        \a     An apostrophe '
        \b     A carriage return (ASCII 13)
        \e     An escape (ASCII 27)
        \n     A linefeed (ASCII 10)
        \q     A double quote (ASCII 34)
        \t     A tab (ASCII 9)
        \\     A backslash \

An apostrophe can also be produced by typing two apostrophes in a row in a
string.  It's best to use this only in the middle of a string, where it's
nice and obvious:

       WriteF('Here\as an apostrophe.\n')       /* Using \a */
     
       WriteF('Here''s another apostrophe.\n')  /* Using '' */


@EndNode

@Node "Named Constants" "beginner.guide/Named Constants"
@Next "Enumerations"
@Prev "String Constants Special Character Sequences"
@Toc "Constants"

Named Constants
===============

   It is often nice to be able to give names to certain constants.  For
instance, as we saw earlier, the truth value @{b}TRUE@{ub} actually represents the
value -1, and @{b}FALSE@{ub} represents zero (see @{"Logic and comparison" Link "Logic and comparison"}).  These are
our first examples of named constants.  To define your own you use the
@{b}CONST@{ub} keyword as follows:

     CONST ONE=1, LINEFEED=10, BIG_NUM=999999

This has defined the constant @{b}ONE@{ub} to represent one, @{b}LINEFEED@{ub} ten and
@{b}BIG_NUM@{ub} 999,999.  Named constants must begin with two uppercase letters,
as mentioned before (see @{"Identifiers" Link "Identifiers"}).

   You can use previously defined constants to give the value of a new
constant, but in this case the definitions must occur on different @{b}CONST@{ub}
lines.

     CONST ZERO=0
     CONST ONE=ZERO+1
     CONST TWO=ONE+1

The expression used to define the value of a constant can use only simple
operators (no function calls) and constants.


@EndNode

@Node "Enumerations" "beginner.guide/Enumerations"
@Next "Sets"
@Prev "Named Constants"
@Toc "Constants"

Enumerations
============

   Often you want to define a whole lot of constants and you just want
them all to have a different value so you can tell them apart easily.  For
instance, if you wanted to define some constants to represent some famous
cities and you only needed to know how to distinguish one from another
then you could use an @{fg shine}enumeration@{fg text} like this:

     ENUM LONDON, MOSCOW, NEW_YORK, PARIS, ROME, TOKYO

The @{b}ENUM@{ub} keyword begins the definitions (like the @{b}CONST@{ub} keyword does for
an ordinary constant definition).  The actual values of the constants
start at zero and stretch up to five.  In fact, this is exactly the same
as writing:

     CONST LONDON=0, MOSCOW=1, NEW_YORK=2, PARIS=3, ROME=4, TOKYO=5

   The enumeration does not have to start at zero, though.  You can change
the starting value at any point by specifying a value for an enumerated
constant.  For example, the following constant definitions are equivalent:

     ENUM APPLE, ORANGE, CAT=55, DOG, GOLDFISH, FRED=-2,
          BARNEY, WILMA, BETTY
     
     CONST APPLE=0, ORANGE=1, CAT=55, DOG=56, GOLDFISH=57,
           FRED=-2, BARNEY=-1, WILMA=0, BETTY=1


@EndNode

@Node "Sets" "beginner.guide/Sets"
@Prev "Enumerations"
@Toc "Constants"

Sets
====

   Yet another kind of constant definition is the @{fg shine}set@{fg text} definition.  This
useful for defining flag sets, i.e., a number of options each of which can
be on or off.  The definition is like a simple enumeration, but using the
@{b}SET@{ub} keyword and this time the values start at one and increase as powers
of two (so the next value is two, the next is four, the next eight, and so
on).  Therefore, the following definitions are equivalent:

     SET ENGLISH, FRENCH, GERMAN, JAPANESE, RUSSIAN
     
     CONST ENGLISH=1, FRENCH=2, GERMAN=4, JAPANESE=8, RUSSIAN=16

However, the significance of the values it is best shown by using binary
constants:

     CONST ENGLISH=%00001, FRENCH=%00010, GERMAN=%00100,
           JAPANESE=%01000, RUSSIAN=%10000

If a person speaks just English then we can use the constant @{b}ENGLISH@{ub}.  If
they also spoke Japanese then to represent this with a single value we'd
normally need a new constant (something like @{b}ENG_JAP@{ub}).  In fact, we'd
probably need a constant for each combination of languages a person might
know.  However, with the set definition we can @{b}OR@{ub} the @{b}ENGLISH@{ub} and @{b}JAPANESE@{ub}
values together to get a new value, @{b}%01001@{ub}, and this represents a set
containing both @{b}ENGLISH@{ub} and @{b}JAPANESE@{ub}.  On the other hand, to find out if
someone speaks French we would @{b}AND@{ub} the value for the languages they know
with @{b}%00010@{ub} (or the constant @{b}FRENCH@{ub}).  (As you might have guessed, @{b}AND@{ub} and
@{b}OR@{ub} are really bit-wise operators, not simply logical operators.  See
@{"Bitwise AND and OR" Link "Bitwise AND and OR"}.)

   Consider this program fragment:

       speak:=GERMAN OR ENGLISH OR RUSSIAN  /* Speak any of these */
       IF speak AND JAPANESE
         WriteF('Can speak in Japanese\n')
       ELSE
         WriteF('Unable to speak in Japanese\n')
       ENDIF
       IF speak AND (GERMAN OR FRENCH)
         WriteF('Can speak in German or French\n')
       ELSE
         WriteF('Unable to speak in German or French\n')
       ENDIF

The assignment sets @{b}speak@{ub} to show that the person can speak in German,
English or Russian.  The first @{b}IF@{ub} block tests whether the person can speak
in Japanese, and the second tests whether they can speak in German or
French.

   When using sets be careful you don't get tempted to add values instead
of @{b}OR@{ub}-ing them.  Adding two different constants from the same set is the
same as @{b}OR@{ub}-ing them, but adding a constant to itself isn't.  This is not
the only time addition doesn't give the same answer, but it's the most
obvious.  If you to stick to using @{b}OR@{ub} you won't have a problem.


@EndNode

@Node "Types" "beginner.guide/Types"
@Next "More About Statements and Expressions"
@Prev "Constants"
@Toc "Main"

Types
*****

   We've already met the @{b}LONG@{ub} type and found that this was the normal type
for variables (see @{"Variable types" Link "Variable types"}).  The types @{b}INT@{ub} and @{b}LIST@{ub} were also
mentioned.  Learning how to use types in an effective and readable way is
very important.  The type of a variable (as well as its name) can give
clues to the reader about how or for what it is used.  There are also more
fundamental reasons for needing types, e.g., to logically group data using
objects (see @{"OBJECT Type" Link "OBJECT Type"}).

   This is a very large chapter and you might like to take it slowly.  One
of the most important things to get to grips with is @{fg shine}pointers@{fg text}.
Concentrate on trying to understand these as they play a large part in any
kind of system programming.


 @{" LONG Type " Link "LONG Type"} 
 @{" PTR Type " Link "PTR Type"} 
 @{" ARRAY Type " Link "ARRAY Type"} 
 @{" OBJECT Type " Link "OBJECT Type"} 
 @{" LIST and STRING Types " Link "LIST and STRING Types"} 
 @{" Linked Lists " Link "Linked Lists"} 


@EndNode

@Node "LONG Type" "beginner.guide/LONG Type"
@Next "PTR Type"
@Toc "Types"

@{b}LONG@{ub} Type
=========

   The @{b}LONG@{ub} type is the most important type because it is the default type
and by far the most common type.  It can be used to store a variety of
data, including @{fg shine}memory addresses@{fg text}, as we shall see.


 @{" Default type " Link "Default type"} 
 @{" Memory addresses " Link "Memory addresses"} 


@EndNode

@Node "Default type" "beginner.guide/Default type"
@Next "Memory addresses"
@Toc "LONG Type"

Default type
------------

   @{b}LONG@{ub} is the default type of variables.  It is a 32-bit type, meaning
that 32-bits of memory (RAM) are used to store the data for each variable
of this type and the data can take (integer) values in the range
-2,147,483,648 to 2,147,483,647.  Variables default to being @{b}LONG@{ub} typed,
but they can also be explicitly declared as @{b}LONG@{ub}:

     DEF x:LONG, y
     
     PROC fred(p:LONG, q, r:LONG)
       DEF zed:LONG
       @{fg shine}statements@{fg text}
     ENDPROC

The global variable @{b}x@{ub}, procedure parameters @{b}p@{ub} and @{b}r@{ub}, and local variable
@{b}zed@{ub} have all been declared to be @{b}LONG@{ub} values.  The declarations are
very similar to the kinds we've seen before, except that the variables
have @{b}:LONG@{ub} after their name in the declaration.  This is the way the type
of a variable is given.  Note that the global variable @{b}y@{ub} and the procedure
parameter @{b}q@{ub} are also @{b}LONG@{ub}, since they do not have a type specified and
@{b}LONG@{ub} is the default type for variables.


@EndNode

@Node "Memory addresses" "beginner.guide/Memory addresses"
@Prev "Default type"
@Toc "LONG Type"

Memory addresses
----------------

   There's a very good reason why @{b}LONG@{ub} is the normal type.  A 32-bit
(integer) value can be used as a @{fg shine}memory address@{fg text}.  Therefore we can store
the address (or location) of data in a variable (the variable is then
called a @{fg shine}pointer@{fg text}).  The variable would then not contain the value of the
data but a way of finding the data.  Once the data location is known the
data can be read or even altered!  The next section covers pointers and
addresses in more detail.  See @{"PTR Type" Link "PTR Type"}.


@EndNode

@Node "PTR Type" "beginner.guide/PTR Type"
@Next "ARRAY Type"
@Prev "LONG Type"
@Toc "Types"

@{b}PTR@{ub} Type
========

   The @{b}PTR@{ub} type is used to hold memory addresses.  Variables which have a
@{b}PTR@{ub} type are called @{fg shine}pointers@{fg text} (since they store memory addresses, as
mentioned in the previous section).  This section describes, in detail,
addresses, pointers and the @{b}PTR@{ub} type.


 @{" Addresses " Link "Addresses"} 
 @{" Pointers " Link "Pointers"} 
 @{" Indirect types " Link "Indirect types"} 
 @{" Finding addresses (making pointers) " Link "Finding addresses (making pointers)"} 
 @{" Extracting data (dereferencing pointers) " Link "Extracting data (dereferencing pointers)"} 
 @{" Procedure parameters " Link "Procedure parameters"} 


@EndNode

@Node "Addresses" "beginner.guide/Addresses"
@Next "Pointers"
@Toc "PTR Type"

Addresses
---------

   To understand memory addresses, a good analogy is to think of memory as
a road or street, each memory location as a post-box on a house, and each
piece of data as a letter.  If you were a postman you would need to know
where to put your letters, and this information is given by the address of
the post-box.  As time goes by, each post-box is filled with different
letters.  This is like the value in a memory location (or variable)
changing.  To change the letters stored in your post-box, you tell your
friends your address and they can send letters in and fill it.  This is
like letting some program change your data by giving it the address of the
data.

   The next two diagrams illustrate this analogy.  A letter contains an
address which points to a particular house (or lot of mail) on a street.

            +-------+
            | Letter|
            |-------|
            |Address+----*
            +-------+     \
                           \
                            \
              +--------+ +---\----+ +--------+     +--------+
              | House  | | House  | | House  |     | House  |
     Street:  |+------+| |+------+| |+------+| ... |+------+|
              || Mail || || Mail || || Mail ||     || Mail ||
              +========+ +========+ +========+     +========+

A pointer contains an address which points to a variable (or data) in
memory.

            +-------+
            |Pointer|
            |-------|
            |Address+----*
            +-------+     \
                           \
                            \
              +--------+ +---\----+ +--------+     +--------+
              |Variable| |Variable| |Variable|     |Variable|
     Memory:  |+------+| |+------+| |+------+| ... |+------+|
              || Data || || Data || || Data ||     || Data ||
              +========+ +========+ +========+     +========+


@EndNode

@Node "Pointers" "beginner.guide/Pointers"
@Next "Indirect types"
@Prev "Addresses"
@Toc "PTR Type"

Pointers
--------

   Variables which contain memory addresses are called @{fg shine}pointers@{fg text}.  As we
saw in the previous section, we can store memory addresses in @{b}LONG@{ub}
variables.  However, we then don't know the type of the data stored at
those addresses.  If it is important (or useful) to know this then the @{b}PTR@{ub}
type (or, more accurately, one of the many @{b}PTR@{ub} types) should be used.

     DEF p:PTR TO LONG, i:PTR TO INT,
         cptr:PTR TO CHAR, gptr:PTR TO gadget

The values stored in each of @{b}p@{ub}, @{b}cptr@{ub}, @{b}i@{ub} and @{b}gptr@{ub} are @{b}LONG@{ub} since they are
memory addresses.  However, the data at the address stored in @{b}p@{ub} is taken
to be @{b}LONG@{ub} (a 32-bit value), that at @{b}cptr@{ub} is @{b}CHAR@{ub} (an 8-bit value), that
at @{b}i@{ub} is @{b}INT@{ub} (a 16-bit value), and that at @{b}gptr@{ub} is @{b}gadget@{ub}, which is an
@{fg shine}object@{fg text} (see @{"OBJECT Type" Link "OBJECT Type"}).


@EndNode

@Node "Indirect types" "beginner.guide/Indirect types"
@Next "Finding addresses (making pointers)"
@Prev "Pointers"
@Toc "PTR Type"

Indirect types
--------------

   In the previous example we saw @{b}INT@{ub} and @{b}CHAR@{ub} used as the destination
types of pointers, and these are the 16- and 8-bit equivalents
(respectively) of the @{b}LONG@{ub} type.  However, unlike @{b}LONG@{ub} these types cannot
be used directly to declare global or local variables, or procedure
parameters.  They can only be used in constructing types (for instance
with @{b}PTR TO@{ub}).  The following declarations are therefore @{i}illegal@{ui}, and it
might be nice to try compiling a little program with such a declaration,
just to see the error message the E compiler gives.

     /* This program fragment contains illegal declarations */
     DEF c:CHAR, i:INT
     
     /* This program fragment contains illegal declarations */
     PROC fred(a:INT, b:CHAR)
       DEF x:INT
       @{fg shine}statements@{fg text}
     ENDPROC

   This is not much of a limitation because you can store @{b}INT@{ub} or @{b}CHAR@{ub}
values in @{b}LONG@{ub} variables if you really need to.  However, it does mean
there's a nice, simple rule: every direct value in E is a 32-bit quantity,
either a @{b}LONG@{ub} or a pointer.  In fact, @{b}LONG@{ub} is actually short-hand for @{b}PTR
TO CHAR@{ub}, so you can use @{b}LONG@{ub} values like they were actually @{b}PTR TO CHAR@{ub}
values.


@EndNode

@Node "Finding addresses (making pointers)" "beginner.guide/Finding addresses (making pointers)"
@Next "Extracting data (dereferencing pointers)"
@Prev "Indirect types"
@Toc "PTR Type"

Finding addresses (making pointers)
-----------------------------------

   If a program knows the address of a variable it can directly read or
alter the value stored in the variable.  To obtain the address of a simple
variable you use @{b}{@{ub} and @{b}}@{ub} around the variable name.  The address of
non-simple variables (e.g., objects and arrays) can be found much more
easily (see the appropriate section), and in fact you will very rarely
need to use @{b}{@{ub}@{fg shine}var@{fg text} @{b} }@{ub}.  However, if you understand how to explicitly
make pointers with @{b}{@{ub}@{fg shine}var@{fg text} @{b} }@{ub} and use the pointers to get to data, then
you'll understand the way pointers are used for the non-simple types much
more quickly.

   Addresses can be stored in a variable, passed to a procedure or
whatever (they're just 32-bit values).  Try out the following program:

     DEF x
     
     PROC main()
       fred(2)
     ENDPROC
     
     PROC fred(y)
       DEF z
       WriteF('x is at address \d\n', {x})
       WriteF('y is at address \d\n', {y})
       WriteF('z is at address \d\n', {z})
       WriteF('fred is at address \d\n', {fred})
     ENDPROC

Notice that you can also find the address of a procedure using @{b}{@{ub} and @{b}}@{ub}.
This is is the memory location of the code the procedure represents.
Here's the output from one execution of this program (don't expect your
output to be exactly the same, though):

     x is at address 3758280
     y is at address 3758264
     z is at address 3758252
     fred is at address 3732878

This is an interesting program to run several times under different
circumstances.  You should see that sometimes the numbers for the
addresses change.  Running the program when another is multi-tasking (and
eating memory) should produce the best changes, whereas running it
consecutively (in one CLI) should produce the smallest (if any) changes.
This gives you a glimpse at the complex memory handling of the Amiga and
the E compiler.


@EndNode

@Node "Extracting data (dereferencing pointers)" "beginner.guide/Extracting data (dereferencing pointers)"
@Next "Procedure parameters"
@Prev "Finding addresses (making pointers)"
@Toc "PTR Type"

Extracting data (dereferencing pointers)
----------------------------------------

   If you have an address stored in a variable (i.e., a pointer) you can
extract the data using the @{b}^@{ub} operator.  This act of extracting data via a
pointer is called @{fg shine}dereferencing@{fg text} the pointer.  This operator should only
really be used when @{b}{@{ub}@{fg shine}var@{fg text} @{b} }@{ub} has been used to obtain an address.  To
this end, @{b}LONG@{ub} values are read and written when dereferencing pointers in
this way.  For pointers to non-simple types (e.g., objects and arrays),
dereferencing is achieved in much more readable ways (see the appropriate
section for details), and this operator is not used.  In fact, @{b} ^@{ub}@{fg shine}var@{fg text}@{b}@{ub} is
seldom used in programs, but is useful for explaining how pointers work,
especially in conjunction with @{b}{@{ub}@{fg shine}var@{fg text} @{b} }@{ub}.

   Using pointers can remove the scope restriction on local variables,
i.e., they can be altered from outside the procedure for which they are
local.  Whilst this kind of use is not generally advised, it makes for a
good example which shows the power of pointers.  For example, the
following program changes the value of the local variable @{b}x@{ub} for the
procedure @{b}fred@{ub} from within the procedure @{b}barney@{ub}.

     PROC main()
       fred()
     ENDPROC
     
     PROC fred()
       DEF x, p:PTR TO LONG
       x:=33
       p:={x}
       barney(p)
       WriteF('x is now \d\n', x)
     ENDPROC
     
     PROC barney(ptr:PTR TO LONG)
       DEF val
       val:=^ptr
       ^ptr:=val-6
     ENDPROC

Here's what you can expect it to generate as output:

     x is now 27

Notice that the @{b}^@{ub} operator (i.e., dereferencing) is quite versatile.  In
the first assignment of the procedure @{b}barney@{ub} it is used (with the pointer
@{b}ptr@{ub}) to get the value stored in the local variable @{b}x@{ub}, and in the second it
is used to change this variable's value.  In either case, dereferencing
makes the pointer behave exactly as if you'd written the variable for
which it is a pointer.  To emphasise this, we can remove the @{b}barney@{ub}
procedure, like we did above (see @{"Style Reuse and Readability" Link "Style Reuse and Readability"}):

     PROC main()
       fred()
     ENDPROC
     
     PROC fred()
       DEF x, p:PTR TO LONG, val
       x:=33
       p:={x}
       val:=x
       x:=val-6
       WriteF('x is now \d\n', x)
     ENDPROC

Everywhere the @{b}barney@{ub} procedure used @{b}^ptr@{ub} we've written @{b}x@{ub} (because we are
now in the procedure for which @{b}x@{ub} is local).  We've also eliminated the @{b}ptr@{ub}
variable (the parameter to the @{b}barney@{ub} procedure), since it was only used
with the @{b}^@{ub} operator.

   To make things clear the @{b}fred@{ub} and @{b}barney@{ub} example is deliberately
`wordy'.  The @{b}val@{ub} and @{b}p@{ub} variables are unnecessary, and the pointer types
could be abbreviated to @{b}LONG@{ub} or even omitted, for the reasons outlined
above (see @{"LONG Type" Link "LONG Type"}).  This is the compact form of the example:

     PROC main()
       fred()
     ENDPROC
     
     PROC fred()
       DEF x
       x:=33
       barney({x})
       WriteF('x is now \d\n', x)
     ENDPROC
     
     PROC barney(ptr)
       ^ptr:=^ptr-6
     ENDPROC

   By far the most common use of pointers is to address (or reference)
large structures of data.  It would be extremely expensive (in terms of
CPU time) to pass large amounts of data from procedure to procedure, so
addresses to such data are passed instead (and, as we know, these are just
32-bit values).  The Amiga system functions (such as ones for creating
windows) require a lot of structured data, so if you plan to do any real
programming you are going to have to understand and use pointers.


@EndNode

@Node "Procedure parameters" "beginner.guide/Procedure parameters"
@Prev "Extracting data (dereferencing pointers)"
@Toc "PTR Type"

Procedure parameters
--------------------

   Only local and global variables have the luxury of a large choice of
types.  Procedure parameters can only be @{b}LONG@{ub} or @{b}PTR TO @{ub}@{fg shine}type@{fg text}@{b}@{ub}.  This is
not really a big limitation as we shall see in the later sections.


@EndNode

@Node "ARRAY Type" "beginner.guide/ARRAY Type"
@Next "OBJECT Type"
@Prev "PTR Type"
@Toc "Types"

@{b}ARRAY@{ub} Type
==========

   Quite often, the data used by a program needs to be ordered in some
way, primarily so that it can be accessed easily.  E provides a way to
achieve such simple ordering: the @{b}ARRAY@{ub} type.  This type (in its various
forms) is common to most computer languages.


 @{" Tables of data " Link "Tables of data"} 
 @{" Accessing array data " Link "Accessing array data"} 
 @{" Array pointers " Link "Array pointers"} 
 @{" Point to other elements " Link "Point to other elements"} 
 @{" Array procedure parameters " Link "Array procedure parameters"} 


@EndNode

@Node "Tables of data" "beginner.guide/Tables of data"
@Next "Accessing array data"
@Toc "ARRAY Type"

Tables of data
--------------

   Data can be grouped together in many different ways, but probably the
most common and straight-forward way is to make a table.  In a table the
data is ordered either vertically or horizontally, but the important thing
is the relative positioning of the elements.  The E view of this kind of
ordered data is the @{b}ARRAY@{ub} type.  An @{fg shine}array@{fg text} is just a fixed sized
collection of data in order.  The size of an array is important and this
is fixed when it is declared.  The following illustrates array
declarations:

     DEF a[132]:ARRAY,
         table[21]:ARRAY OF LONG,
         ints[3]:ARRAY OF INT,
         objs[54]:ARRAY OF myobject

The size of the array is given in the square brackets (@{b}[@{ub} and @{b}]@{ub}).  The type
of the elements in the array defaults to @{b}CHAR@{ub}, but this can be given
explicitly using the @{b}OF@{ub} keyword and the type name.  However, only @{b}LONG@{ub},
@{b}INT@{ub}, @{b}CHAR@{ub} and object types are allowed (@{b}LONG@{ub} can hold pointer values
so this isn't much of a limitation).  Object types are described below
(see @{"OBJECT Type" Link "OBJECT Type"}).

   As mentioned above, procedure parameters cannot be arrays (see
@{"Procedure parameters" Link "Procedure parameters"}).  We will overcome this limitation soon (see
@{"Array procedure parameters" Link "Array procedure parameters"}).


@EndNode

@Node "Accessing array data" "beginner.guide/Accessing array data"
@Next "Array pointers"
@Prev "Tables of data"
@Toc "ARRAY Type"

Accessing array data
--------------------

   To access a particular element in an array you use square brackets
again, this time specifying the @{fg shine}index@{fg text} (or position) of the element you
want.  Indices start at zero for the first element of the array, one for
the second element and, in general, (n-1) for the n-th element.  This may
seem strange at first, but it's the way most computer languages do it!  We
will see a reason why this makes sense soon (see @{"Array pointers" Link "Array pointers"}).

     DEF a[10]:ARRAY
     
     PROC main()
       DEF i
       FOR i:=0 TO 9
         a[i]:=i*i
       ENDFOR
       WriteF('The 7th element of the array a is \d\n', a[6])
       a[a[2]]:=10
       WriteF('The array is now:\n')
       FOR i:=0 TO 9
         WriteF(' a[\d] = \d\n', i, a[i])
       ENDFOR
     ENDPROC

This should all seem very straight-forward although one of the lines looks
a bit complicated.  Try to work out what happens to the array after the
assignment immediately following the first @{b}WriteF@{ub}.  In this assignment the
index comes from a value stored in the array itself!  Be careful when
doing complicated things like this, though: make sure you don't try to
read data from or write data to elements beyond the end of the array.  In
our example there are only ten elements in the array @{b}a@{ub}, so it wouldn't be
sensible to talk about the eleventh element.  The program could have
checked that the value stored at @{b}a[2]@{ub} was a number between zero and nine
before trying to access that array element, but it wasn't necessary in
this case.  Here's the output this example should generate:

     The 7th element of the array a is 36
     The array is now:
      a[0] = 0
      a[1] = 1
      a[2] = 4
      a[3] = 9
      a[4] = 10
      a[5] = 25
      a[6] = 36
      a[7] = 49
      a[8] = 64
      a[9] = 81

   If you do try to write to a non-existent array element strange things
can happen.  This may be practically unnoticeable (like corrupting some
other data), but if you're really unlucky you might crash your computer.
The moral is: stay within the bounds of the array.

   A short-hand for the first element of an array (i.e., the one with an
index of zero) is to omit the index and write only the square brackets.
Therefore, @{b}a[]@{ub} is the same as @{b}a[0]@{ub}.


@EndNode

@Node "Array pointers" "beginner.guide/Array pointers"
@Next "Point to other elements"
@Prev "Accessing array data"
@Toc "ARRAY Type"

Array pointers
--------------

   When you declare an array the address of the (beginning of the) array
is given by the variable name without square brackets.  Consider the
following program:

     DEF a[10]:ARRAY OF INT
     
     PROC main()
       DEF ptr:PTR TO INT, i
       FOR i:=0 TO 9
         a[i]:=i
       ENDFOR
       ptr:=a
       ptr++
       ptr[]:=22
       FOR i:=0 TO 9
         WriteF('a[\d] is \d\n', i, a[i])
       ENDFOR
     ENDPROC

Here's the output from it:

     a[0] is 0
     a[1] is 22
     a[2] is 2
     a[3] is 3
     a[4] is 4
     a[5] is 5
     a[6] is 6
     a[7] is 7
     a[8] is 8
     a[9] is 9

You should notice that the second element of the array has been changed
using the pointer.  The @{b}ptr++@{ub} statement increments the pointer @{b}ptr@{ub} to
point to the next element of the array.  It is important that @{b}ptr@{ub} is
declared as @{b}PTR TO INT@{ub} since the array is an @{b}ARRAY OF INT@{ub}.  The @{b}[]@{ub} is used
to dereference the pointer and therefore 22 is stored in the second
element of the array.  In fact, the @{b}ptr@{ub} can be used in exactly the same
way as an array, so @{b}ptr[1]@{ub} would be the next (or third element) of the
array @{b}a@{ub} (after the @{b}ptr++@{ub} statement).  Also, since @{b}ptr@{ub} points to the second
element of @{b}a@{ub}, negative values may legitimately be used as the index, and
@{b}ptr[-1]@{ub} is the first element of @{b}a@{ub}.

   In fact, the following declarations are identical except the first
reserves an appropriate amount of memory for the array whereas the second
relies on you having done this somewhere else in the program.

       DEF a[20]:ARRAY OF INT
     
       DEF a:PTR TO INT

   The following diagram is similar to the diagrams given earlier (see
@{"Addresses" Link "Addresses"}).  It is an illustration of an array, @{b}a@{ub}, which was declared to
be an array of twenty @{b}INT@{ub}s.

         +--------+
         |Variable|
         |  'a'   |
         |--------|
         | Address+----*
         +--------+     \
                         \
                          \
              +-------+ +--\----+ +-------+     +-------+ +-------+
              |Unknown| | a[0]  | | a[1]  |     | a[19] | |Unknown|
     Memory:  |+-----+| |+-----+| |+-----+| ... |+-----+| |+-----+|
              || XXX || || INT || || INT ||     || INT || || XXX ||
              +=======+ +=======+ +=======+     +=======+ +=======+

As you can see, the variable @{b}a@{ub} is a pointer to the reserved chunk of
memory which contains the array elements.  Parts of memory that aren't
between @{b}a[0]@{ub} and @{b}a[19]@{ub} are marked as `Unknown' because they are not part
of the array.  This memory should therefore not be accessed using the
array @{b}a@{ub}.


@EndNode

@Node "Point to other elements" "beginner.guide/Point to other elements"
@Next "Array procedure parameters"
@Prev "Array pointers"
@Toc "ARRAY Type"

Point to other elements
-----------------------

   We saw in the previous section how to increment a pointer so that it
points to the next element in the array.  Decrementing a pointer @{b}p@{ub} (i.e.,
making it point to the previous element) is done in a similar way, using
the @{b}p--@{ub} statement which works in the same way as the @{b}p++@{ub} statement.  In
fact, @{b}p++@{ub} and @{b}p--@{ub} are really expressions which denote pointer values.  @{b}p++@{ub}
denotes the address stored in @{b}p@{ub} @{i}before@{ui} it is incremented, and @{b}p--@{ub} denotes
the address @{i}after@{ui} @{b}p@{ub} is decremented.  Therefore,

       addr:=p
       p++

does the same as

       addr:=p++

And

       p--
       addr:=p

does the same as

       addr:=p--

   The reason why @{b}++@{ub} and @{b}--@{ub} should be used to increment and decrement a
pointer is that values from different types occupy different numbers of
memory locations.  In fact, a single memory location is a @{fg shine}byte@{fg text}, and this
is eight bits.  Therefore, @{b}CHAR@{ub} values occupy a single byte, whereas @{b}LONG@{ub}
values take up four bytes (32 bits).  If @{b}p@{ub} were a pointer to @{b}CHAR@{ub} and it
was pointing to an array (of @{b}CHAR@{ub}) the @{b}p+1@{ub} memory location would contain
the second element of the array (and @{b}p+2@{ub} the third, etc.).  But if @{b}p@{ub} were
a pointer to an array of @{b}LONG@{ub} the second element in the array would be at
@{b}p+4@{ub} (and the third at @{b}p+8@{ub}).  The locations @{b}p@{ub}, @{b}p+1@{ub}, @{b}p+2@{ub} and @{b}p+3@{ub} all make up
the @{b}LONG@{ub} value at address @{b}p@{ub}.  Having to remember things like this is a
pain, and it's a lot less readable than using @{b}++@{ub} or @{b}--@{ub}.  However, you must
remember to declare your pointer with the correct type in order for @{b}++@{ub} and
@{b}--@{ub} to work correctly.


@EndNode

@Node "Array procedure parameters" "beginner.guide/Array procedure parameters"
@Prev "Point to other elements"
@Toc "ARRAY Type"

Array procedure parameters
--------------------------

   Since we now know how to get the address of an array we can simulate
passing an array as a procedure parameter by passing the address of the
array.  For example, the following program uses a procedure to fill in the
first @{b}x@{ub} elements of an array with their index numbers.

     DEF a[10]:ARRAY OF INT
     
     PROC main()
       DEF i
       fillin(a, 10)
       FOR i:=0 TO 9
         WriteF('a[\d] is \d\n', i, a[i])
       ENDFOR
     ENDPROC
     
     PROC fillin(ptr:PTR TO INT, x)
       DEF i
       FOR i:=0 TO x-1
         ptr[]:=i
         ptr++
       ENDFOR
     ENDPROC

Here's the output it should generate:

     a[0] is 0
     a[1] is 1
     a[2] is 2
     a[3] is 3
     a[4] is 4
     a[5] is 5
     a[6] is 6
     a[7] is 7
     a[8] is 8
     a[9] is 9

The array @{b}a@{ub} only has ten elements so we shouldn't fill in any more than
the first ten elements.  Therefore, in the example, the call to the
procedure @{b}fillin@{ub} should not have a bigger number than ten as the second
parameter.  Also, we could treat @{b}ptr@{ub} more like an array (and not use @{b}++@{ub}),
but in this case using @{b}++@{ub} is slightly better since we are assigning to
each element in turn.  The alternative definition of @{b}fillin@{ub} (without using
@{b}++@{ub}) is:

     PROC fillin2(ptr:PTR TO INT, x)
       DEF i
       FOR i:=0 TO x-1
         ptr[i]:=i
       ENDFOR
     ENDPROC

Also, yet another version of @{b}fillin@{ub} uses the expression form of @{b}++@{ub} and the
horizontal form of the @{b}FOR@{ub} loop to give a really compact definition.

     PROC fillin3(ptr:PTR TO INT, x)
       DEF i
       FOR i:=0 TO x-1 DO ptr[]++:=i
     ENDPROC


@EndNode

@Node "OBJECT Type" "beginner.guide/OBJECT Type"
@Next "LIST and STRING Types"
@Prev "ARRAY Type"
@Toc "Types"

@{b}OBJECT@{ub} Type
===========

   Objects are the E equivalent of C and Assembly structures, or Pascal
records.  They are like arrays except the elements are named not numbered,
and the elements can be of different types.  To find a particular element
in an object you use a name instead of an index (number).  Objects are
also the basis of the OOP features of E (see @{"Object Oriented E" Link "Object Oriented E"}).


 @{" Example object " Link "Example object"} 
 @{" Element selection and element types " Link "Element selection and element types"} 
 @{" Amiga system objects " Link "Amiga system objects"} 


@EndNode

@Node "Example object" "beginner.guide/Example object"
@Next "Element selection and element types"
@Toc "OBJECT Type"

Example object
--------------

   We'll dive straight in with this first example, and define an object
and use it.  Object definitions are global and must be made before any
procedure definitions.

     OBJECT rec
       tag, check
       table[8]:ARRAY
       data:LONG
     ENDOBJECT
     
     PROC main()
       DEF a:rec
       a.tag:=1
       a.check:=a
       a.data:=a.tag+(10000*a.tag)
     ENDPROC

This program doesn't visibly do anything so there isn't much point in
compiling it.  What it does do, however, is show how a typical object is
defined and elements of an object are selected.

   The object being defined in the example is @{b}rec@{ub}, and its elements are
defined just like variable declarations (but without a @{b}DEF@{ub}).  There can be
as many lines of element definitions as you like between the @{b}OBJECT@{ub} and
@{b}ENDOBJECT@{ub} lines, and each line can contain any number of elements
separated by commas.  The elements of the @{b}rec@{ub} object are @{b}tag@{ub} and @{b}check@{ub}
(which are @{b}LONG@{ub}), @{b}table@{ub} (which is an array of @{b}CHAR@{ub} with eight elements)
and @{b}data@{ub} (which is also @{b}LONG@{ub}).  Every variable of @{b}rec@{ub} object type will
have space reserved for each of these elements.  The declaration of the
(local) variable @{b}a@{ub} therefore reserves enough memory for one @{b}rec@{ub} object.


@EndNode

@Node "Element selection and element types" "beginner.guide/Element selection and element types"
@Next "Amiga system objects"
@Prev "Example object"
@Toc "OBJECT Type"

Element selection and element types
-----------------------------------

   To select elements in an object @{b}obj@{ub} you use @{b}obj.name@{ub}, where @{b}name@{ub} is one
of the element names.  In the example, the @{b}tag@{ub} element of the @{b}rec@{ub} object @{b}a@{ub}
is selected by writing @{b}a.tag@{ub}.  The other elements are selected in a
similar way.

   Just like an array declaration the address of an object @{b}obj@{ub} is stored
in the variable @{b}obj@{ub}, and any pointer of type @{b}PTR TO @{ub}@{fg shine}objectname@{fg text}@{b}@{ub} can be
used just like an object of type @{fg shine}objectname@{fg text}.  Therefore, in the previous
example @{b}a@{ub} is a @{b}PTR TO rec@{ub}.

   As the example object shows, the elements of an object can have several
different types.  In fact, the elements can have any type, including
object, pointer to object and array of object.  The following example
shows how to access some different typed elements.

     OBJECT rec
       tag, check
       table[8]:ARRAY
       data:LONG
     ENDOBJECT
     
     OBJECT bigrec
       data:PTR TO LONG
       subrec:PTR TO rec
       rectable[22]:ARRAY OF rec
     ENDOBJECT
     
     PROC main()
       DEF r:rec, b:bigrec, rt:PTR TO rec
       r.table[]:="H"
       b.subrec:=r
       b.subrec.tag:=1
       b.subrec.data:=r.tag+(10000*b.subrec.tag)
       b.subrec.table[1]:="i"
       b.rectable[0].data:=r.tag
       b.rectable[0].table[0]:="A"
       rt:=b.rectable
       rt[].data++:=0
       rt[].table[]--:="B"
     ENDPROC

The @{b}++@{ub} and @{b}--@{ub} operators apply to first thing in the selection (i.e., @{b}rt@{ub} in
@{i}both@{ui} the last two assignments in the example above), and may only occur
after all the selections.  Notice that object selection and array indexing
can be repeated as much as necessary (but only as the types of the
elements allow).  As a simple example, consider the third assignment:

       b.subrec.tag:=1

This selects the @{b}subrec@{ub} element from the @{b}bigrec@{ub} object @{b}b@{ub}, and then sets
the @{b}tag@{ub} element of this @{b}rec@{ub} object to 1.  Now, consider one of the later
assignments:

       b.rectable[0].table[0]:="A"

This selects the @{b}rectable@{ub} element from @{b}b@{ub}, which is an array of @{b}rec@{ub} objects.
The first element of this array is selected, and then the @{b}table@{ub} element of
the @{b}rec@{ub} object is selected.  Finally, the first character of the @{b}table@{ub} is
set to the ASCII value of character @{b}A@{ub}.

   As you can probably tell, it is important to give the elements of
objects appropriate types if you want to do multiple selection in this way.
However, this is not always possible or the best way of doing some things,
so there is a way of giving a different type to pointers (this is called
@{fg shine}explicit pointer typing@{fg text}--see the `Reference Manual' for more details).

   Here's a quite simple example which uses an array of objects:

     OBJECT rec
       tag, check
       table[8]:ARRAY
       data:LONG
     ENDOBJECT
     
     PROC main()
       DEF a[10]:ARRAY OF rec, p:PTR TO rec, i
       p:=a
       FOR i:=0 TO 9
         a[i].tag:=i
         p.check++:=i
       ENDFOR
       FOR i:=0 TO 9
         IF a[i].tag<>a[i].check
           WriteF('Whoops, a[\d] went wrong...\n', i)
         ENDIF
       ENDFOR
     ENDPROC

If you think about it for long enough you'll see that @{b}a[0].tag@{ub} is the same
as @{b}a.tag@{ub}.  That's because @{b}a@{ub} is a pointer to the first element of the
array, and the elements of the array are objects.  Therefore, @{b}a@{ub} is a
pointer to an object (the first object in the array).


@EndNode

@Node "Amiga system objects" "beginner.guide/Amiga system objects"
@Prev "Element selection and element types"
@Toc "OBJECT Type"

Amiga system objects
--------------------

   There are many different Amiga system objects.  For instance, there's
one which contains the information needed to make a gadget (like the
`close' gadget on most windows), and one which contains all the
information about a process or task.  These objects are vitally important
and so are supplied with E in the form of `modules'.  Each module is
specific to a certain area of the Amiga system and contains object and
other definitions.  Modules are discussed in more detail later (see
@{"Modules" Link "Modules"}).


@EndNode

@Node "LIST and STRING Types" "beginner.guide/LIST and STRING Types"
@Next "Linked Lists"
@Prev "OBJECT Type"
@Toc "Types"

@{b}LIST@{ub} and @{b}STRING@{ub} Types
=====================

   Arrays are common to many computer languages.  However, they can be a
bit of a pain because you always need to make sure you haven't run off the
end of the array when you're writing to it.  This is where the @{b}STRING@{ub} and
@{b}LIST@{ub} types come in.  @{b}STRING@{ub} is very much like @{b}ARRAY OF CHAR@{ub} and @{b}LIST@{ub} is
like @{b}ARRAY OF LONG@{ub}.  However, each has a set of E (built-in) functions
which safely manipulate variables of these types without exceeding their
bounds.


 @{" Normal strings and E-strings " Link "Normal strings and E-strings"} 
 @{" String functions " Link "String functions"} 
 @{" Lists and E-lists " Link "Lists and E-lists"} 
 @{" List functions " Link "List functions"} 
 @{" Complex types " Link "Complex types"} 
 @{" Typed lists " Link "Typed lists"} 
 @{" Static data " Link "Static data"} 


@EndNode

@Node "Normal strings and E-strings" "beginner.guide/Normal strings and E-strings"
@Next "String functions"
@Toc "LIST and STRING Types"

Normal strings and E-strings
----------------------------

   @{fg shine}Normal@{fg text} strings are common to most programming languages.  They are
simply an array of characters, with the end of the string marked by a null
character (ASCII zero).  We've already met normal strings (see @{"Strings" Link "Strings"}).
The ones we used were constant strings contained in ' characters, and they
denote pointers to the memory where the string data is stored.  Therefore,
you can assign a string constant to a pointer (to @{b}CHAR@{ub}), and you've got an
array with ready-filled elements, i.e., an initialised array.

       DEF s:PTR TO CHAR
       s:='This is a string constant'
       /* Now s[] is T and s[2] is i */

Remember that @{b}LONG@{ub} is actually @{b}PTR TO CHAR@{ub} so this code is precisely the
same as:

       DEF s
       s:='This is a string constant'

The following diagram illustrates the above assignment to @{b}s@{ub}.  The first
two characters @{b}s[0]@{ub} and @{b}s[1]@{ub}) are @{b}T@{ub} and @{b}h@{ub}, and the last character (before
the terminating null, or zero) is @{b}t@{ub}.  Memory marked as `Unknown' is not
part of the string constant.

        +--------+
        |Variable|
        |  's'   |
        |--------|
        |Address +----*
        +--------+     \
                        \
                         \
             +-------+ +--\----+ +-------+   +-------+ +-------+ +-------+
             |Unknown| | s[0]  | | s[1]  |   | s[24] | | s[25] | |Unknown|
     Memory: |+-----+| |+-----+| |+-----+|...|+-----+| |+-----+| |+-----+|
             || XXX || || "T" || || "h" ||   || "t" || ||  0  || || XXX ||
             +=======+ +=======+ +=======+   +=======+ +=======+ +=======+

   @{fg shine}E-strings@{fg text} are very similar to normal strings and, in fact, an
E-string can be used wherever a normal string can.  However, the reverse
is not true, so if something requires an E-string you cannot use a normal
string instead.  The difference between a normal string and an E-string
was hinted at in the introduction to this section: E-strings can be safely
altered without exceeding their bounds.  A normal string is just an array
so you need to be careful not to exceed its bounds.  However, an E-string
knows what its bounds are, and so any of the string manipulation functions
can alter them safely.

   An E-string (@{b}STRING@{ub} type) variable is declared as in the following
example, with the maximum size of the E-string given just like an array
declaration.

       DEF s[30]:STRING

As with an array declaration, the variable @{b}s@{ub} is actually a pointer to the
string data.  To initialise an E-string you need to use the function
@{b}StrCopy@{ub} as we shall see.

   There are some worked examples in Part Three (see
@{"String Handling and I-O" Link "String Handling and I-O"}) which show how to use normal strings and
E-strings.


@EndNode

@Node "String functions" "beginner.guide/String functions"
@Next "Lists and E-lists"
@Prev "Normal strings and E-strings"
@Toc "LIST and STRING Types"

String functions
----------------

   There are a number of useful built-in functions which manipulate
strings.  Remember that if an E-string can be used wherever a normal
string can, but normal strings cannot be used where an E-string is
required.  If a parameter is marked as @{fg shine}string@{fg text} then a normal or E-string
can be passed as that parameter, but if it is marked as @{fg shine}e-string@{fg text} then
only an E-string may be used.  Some of these functions have default
arguments, which means you don't need to specify some parameters to get
the default values (see @{"Default Arguments" Link "Default Arguments"}).  (You can, of course, ignore
the defaults and always give all parameters.)

@{b}String(@{ub}@{fg shine}maxsize@{fg text}@{b})@{ub} 
     Allocates memory for an E-string of maximum size @{fg shine}maxsize@{fg text} and
     returns a pointer to the string data.  It is used to make space for a
     new E-string, like a @{b}STRING@{ub} declaration does.  The following code
     fragments are practically equivalent:

            DEF s[37]:STRING
          
            DEF s:PTR TO CHAR
            s:=String(37)

     The slight difference is that there may not be enough memory left to
     hold the E-string when the @{b}String@{ub} function is used.  In that case the
     special value @{b}NIL@{ub} (a constant) is returned.  Your program @{i}must@{ui} check
     that the value returned is not @{b}NIL@{ub} before you use it as an E-string
     (or dereference it).  The memory for the declaration version is
     allocated when the program is run, so your program won't run if there
     isn't enough memory.  The @{b}String@{ub} version is often called @{fg shine}dynamic@{fg text}
     allocation because it happens only when the program is running; the
     declaration version has allocation done by the E compiler.  The
     memory allocated using @{b}String@{ub} is deallocated using @{b}DisposeLink@{ub} (see
     @{"System support functions" Link "System support functions"}).

@{b}StrCmp(@{ub}@{fg shine}string1@{fg text}@{b},@{ub}@{fg shine}string2@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b}=ALL)@{ub} 
     Compares @{fg shine}string1@{fg text} with @{fg shine}string2@{fg text} (they can both be normal or
     E-strings).  Returns @{b}TRUE@{ub} if the first @{fg shine}length@{fg text} characters of the
     strings match, and @{b}FALSE@{ub} otherwise.  The @{fg shine}length@{fg text} defaults to the
     special constant @{b}ALL@{ub} which means that the strings must agree on every
     character.  For example, the following comparisons all return @{b}TRUE@{ub}:

            StrCmp('ABC',  'ABC')
            StrCmp('ABC',  'ABC', ALL)
            StrCmp('ABCd', 'ABC',    3)
            StrCmp('ABCde','ABCxxjs',3)

     And the following return @{b}FALSE@{ub} (notice the case of the letters):

            StrCmp('ABC',  'ABc')
            StrCmp('ABC',  'ABc', ALL)
            StrCmp('ABCd', 'ABC', ALL)

@{b}StrCopy(@{ub}@{fg shine}e-string@{fg text}@{b},@{ub}@{fg shine}string@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b}=ALL)@{ub} 
     Copies the contents of @{fg shine}string@{fg text} to @{fg shine}e-string@{fg text}, and also returns a
     pointer to the resulting E-string (for convenience).  Only @{fg shine}length@{fg text}
     characters are copied from the source string, but the special
     constant @{b}ALL@{ub} can be used to indicate that the whole of the source
     string is to be copied (and this is the default value for @{fg shine}length@{fg text}).
     Remember that E-strings are safely manipulated, so the following code
     fragment results in @{b}s@{ub} becoming @{b}More th@{ub}, since its maximum size is
     (from its declaration) seven characters.

            DEF s[7]:STRING
            StrCopy(s, 'More than seven characters', ALL)

     A declaration using @{b}STRING@{ub} (or @{b}ARRAY@{ub}) reserves a small part of
     memory, and stores a pointer to this memory in the variable being
     declared.  So to get data into this memory you need to copy it there,
     using @{b}StrCopy@{ub}.  If you're familiar with very high-level languages
     like BASIC you should take care, because you might think you can
     assign a string to an array or an E-string variable.  In E (and
     languages like C and Assembly) you must explicitly copy data into
     arrays and E-strings.  You should not do the following:

            /* You don't want to do things like this! */
            DEF s[80]:STRING
            s:='This is a string constant'

     This is fairly disastrous: it throws away the pointer to reserved
     memory that was stored in @{b}s@{ub} and replaces it by a pointer to the
     string constant.  @{b}s@{ub} is then no longer an E-string, and @{i}cannot@{ui} be
     repaired using @{b}SetStr@{ub}.  If you want @{b}s@{ub} to contain the above string you
     must use @{b}StrCopy@{ub}:

            DEF s[80]:STRING
            StrCopy(s,'This is a string constant')

     The moral is: remember when you are using pointers to data and when
     you need to copy data.  Also, remember that assignment does not copy
     large arrays of data, it only copies pointers to data, so if you want
     to store some data in an @{b}ARRAY@{ub} or @{b}STRING@{ub} type variable you need to
     copy it there.

@{b}StrAdd(@{ub}@{fg shine}e-string@{fg text}@{b},@{ub}@{fg shine}string@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b}=ALL)@{ub} 
     This does the same as @{b}StrCopy@{ub} but the source string is copied onto
     the end of the destination E-string.  The following code fragment
     results in @{b}s@{ub} becoming @{b}This is a string and a half@{ub}.

            DEF s[30]:STRING
            StrCopy(s, 'This is a string', ALL)
            StrAdd(s,  ' and a half')

@{b}StrLen(@{ub}@{fg shine}string@{fg text}@{b})@{ub} 
     Returns the length of @{fg shine}string@{fg text}.  This assumes that the string is
     terminated by a null character (i.e., ASCII zero), which is true for
     any strings made from E-strings and string constants.  However, you
     can make a string constant look short if you use the null character
     (the special sequence @{b}\0@{ub}) in it.  For instance, these calls all
     return three:

            StrLen('abc')
            StrLen('abc\0def')

     In fact, most of the string functions assume strings are
     null-terminated, so you shouldn't use null characters in your strings
     unless you really know what you're doing.

     For E-strings @{b}StrLen@{ub} is less efficient than the @{b}EstrLen@{ub} function.

@{b}EstrLen(@{ub}@{fg shine}e-string@{fg text}@{b})@{ub} 
     Returns the length of @{fg shine}e-string@{fg text} (remember this can only be an
     E-string).  This is much more efficient than @{b}StrLen@{ub} since E-strings
     know their length and it doesn't need to search the string for a null
     character.

@{b}StrMax(@{ub}@{fg shine}e-string@{fg text}@{b})@{ub} 
     Returns the maximum length of @{fg shine}e-string@{fg text}.  This is not necessarily
     the current length of the E-string, rather it is the size used in the
     declaration with @{b}STRING@{ub} or the call to @{b}String@{ub}.

@{b}RightStr(@{ub}@{fg shine}e-string1@{fg text}@{b},@{ub}@{fg shine}e-string2@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b})@{ub} 
     This is like @{b}StrCopy@{ub} but it copies the right-most characters from
     @{fg shine}e-string2@{fg text} to @{fg shine}e-string1@{fg text} and both strings must be E-strings.  At
     most @{fg shine}length@{fg text} characters are copied, and the special constant @{b}ALL@{ub}
     @{i}cannot@{ui} be used (to copy all the string you should, of course, use
     @{b}StrCopy@{ub}).  For instance, a value of one for @{fg shine}length@{fg text} means the last
     character of @{fg shine}e-string2@{fg text} is copied to @{fg shine}e-string1@{fg text}.

@{b}MidStr(@{ub}@{fg shine}e-string@{fg text}@{b},@{ub}@{fg shine}string@{fg text}@{b},@{ub}@{fg shine}index@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b}=ALL)@{ub} 
     Copies the contents of @{fg shine}string@{fg text} starting at @{fg shine}index@{fg text} (which is an
     index just like an array index) to @{fg shine}e-string@{fg text}.  At most @{fg shine}length@{fg text}
     characters are copied, and the special constant @{b}ALL@{ub} can be used if
     all the remaining characters in @{fg shine}string@{fg text} should be copied (this is
     the default value for @{fg shine}length@{fg text}).  For example, the following two
     calls to @{b}MidStr@{ub} result in @{b}s@{ub} becoming @{b}four@{ub}:

            DEF s[30]:STRING
            MidStr(s, 'Just four',      5)
            MidStr(s, 'Just four apples', 5, 4)

@{b}InStr(@{ub}@{fg shine}string1@{fg text}@{b},@{ub}@{fg shine}string2@{fg text}@{b},@{ub}@{fg shine}startindex@{fg text}@{b}=0)@{ub} 
     Returns the index of the first occurrence of @{fg shine}string2@{fg text} in @{fg shine}string1@{fg text}
     starting at @{fg shine}startindex@{fg text} (in @{fg shine}string1@{fg text}).  @{fg shine}startindex@{fg text} defaults to
     zero.  If @{fg shine}string2@{fg text} could not be found then -1 is returned.

@{b}TrimStr(@{ub}@{fg shine}string@{fg text}@{b})@{ub} 
     Returns the address of (i.e., a pointer to) the first non-whitespace
     character in @{fg shine}string@{fg text}.  For instance, the following code fragment
     results in @{b}s@{ub} becoming @{b}12345@{ub}.

            DEF s:PTR TO CHAR
            s:=TrimStr('  \n \t   12345')

@{b}LowerStr(@{ub}@{fg shine}string@{fg text}@{b})@{ub} 
     Converts all uppercase letters in @{fg shine}string@{fg text} to lowercase.  This change
     is made @{fg shine}in-place@{fg text}, i.e., the contents of the string are directly
     affected.  The string is returned for convenience.

@{b}UpperStr(@{ub}@{fg shine}string@{fg text}@{b})@{ub} 
     Converts all lowercase letters in @{fg shine}string@{fg text} to uppercase.  Again, this
     change is made in-place and the string is returned for convenience.

@{b}SetStr(@{ub}@{fg shine}e-string@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b})@{ub} 
     Sets the length of @{fg shine}e-string@{fg text} to @{fg shine}length@{fg text}.  E-strings know how long
     they are, so if you alter an E-string (without using an E-string
     function) and change its size you need to set its length using this
     function before you can use it as an E-string again.  For instance,
     if you've used an E-string like an array (which you can do) and
     written characters to it directly you must set its length before you
     can treat it as anything other than an array/string:

            DEF s[10]:STRING
            s[0]:="a"     /* Remember that "a" is a character value. */
            s[1]:="b"
            s[2]:="c"
            s[3]:="d"     /* At this point s is just an array of CHAR. */
            SetStr(s, 4)  /* Now, s can be used as an E-string again.  */
            SetStr(s, 2)  /* s is a bit shorter, but still an E-string.*/

     Notice that this function can be used to shorten an E-string (but you
     cannot lengthen it this way).

@{b}Val(@{ub}@{fg shine}string@{fg text}@{b},@{ub}@{fg shine}address@{fg text}@{b}=NIL)@{ub} 
     What this function does is straight-forward but how you use it is a
     bit complicated.  Basically, it converts @{fg shine}string@{fg text} to a @{b}LONG@{ub} integer.
     Leading whitespace is ignored, and a leading @{b}%@{ub} or @{b}$@{ub} means that the
     string denotes a binary or hexadecimal integer (in the same way they
     do for numeric constants).  The decoded integer is returned as the
     regular return value (see @{"Multiple Return Values" Link "Multiple Return Values"}).  The number of
     characters of @{fg shine}string@{fg text} that were read to make the integer is stored
     at @{fg shine}address@{fg text}, which is usually a variable address (from using
     @{b}{@{ub}@{fg shine}var@{fg text} @{b} }@{ub}), and is returned as the first
     optional return value.  If @{fg shine}address@{fg text} is the special constant @{b}NIL@{ub} (or zero)
     then this number is not stored (this is the default value for
     @{fg shine}address@{fg text}).  You can use this number to calculate the
     position in the string which was not part of the integer in the
     string.  If an integer could not be decoded from the string then zero
     is returned and zero is stored at @{fg shine}address@{fg text}.

     Follow the comments in this example, and pay special attention to the
     use of the pointer @{b}p@{ub}.

            DEF s[30]:STRING, value, chars, p:PTR TO CHAR
            StrCopy(s, ' \t \n 10 \t $3F -%0101010')
            value, chars:=Val('abcde 10 20')  -> Two return values...
              /* After the above line, value and chars will both be zero */
            value:=Val(s, {chars})          -> Use address of chars
              /* Now value will be 10, chars will be 7 */
            p:=s+chars
              /* p now points to the space after the 10 in s */
            value, chars:=Val(p)
              /* Now value will be $3F (63), chars will be 6 */
            p:=p+chars
              /* p now points to the space after the $3F in s */
            value, chars:=Val(p)
              /* Now value will be -%0101010 (-42), chars will be 10 */

     Notice the two different ways of finding the number of characters
     read: a multiple-assignment and using the address of a variable.

   There's a couple of other string functions (@{b}ReadStr@{ub} and @{b}StringF@{ub}) which
will be discussed later (see @{"Input and output functions" Link "Input and output functions"}).


@EndNode

@Node "Lists and E-lists" "beginner.guide/Lists and E-lists"
@Next "List functions"
@Prev "String functions"
@Toc "LIST and STRING Types"

Lists and E-lists
-----------------

   Lists are just like strings with @{b}LONG@{ub} elements rather than @{b}CHAR@{ub}
elements (so they are very much like @{b}ARRAY OF LONG@{ub}).  The list equivalent
of an E-string is something called an @{fg shine}E-list@{fg text}.  It has the same
properties as an E-string, except the elements are @{b}LONG@{ub} (so could be
pointers).  Normal lists are most like string constants, except that the
elements can be built from variables and so do not have to be constants.
Just as strings are not true E-strings, (normal) lists are not true
E-lists.

   Lists are written using @{b}[@{ub} and @{b}]@{ub} to delimit comma separated elements.
Like string constants a list returns the address of the memory which
contains the elements.

   For example the following code fragment:

       DEF list:PTR TO LONG, number
       number:=22
       list:=[1,2,3,number]

is equivalent to:

       DEF list[4]:ARRAY OF LONG, number
       number:=22
       list[0]:=1
       list[1]:=2
       list[2]:=3
       list[3]:=number

Now, which of these two versions would you rather write?  As you can see,
lists are pretty useful for making your program easier to write and much
easier to read.

   E-list variables are like E-string variables and are declared in much
the same way.  The following code fragment declares @{b}lt@{ub} to be an E-list of
maximum size 30.  As ever, @{b}lt@{ub} is then a pointer (to @{b}LONG@{ub}), and it points
to the memory allocated by the declaration.

       DEF lt[30]:LIST

   Lists are most useful for writing @{fg shine}tag lists@{fg text}, which are increasingly
used in important Amiga system functions.  A tag list is a list where the
elements are thought of in pairs.  The first element of a pair is the tag,
and the second is some data for that tag.  See the `Rom Kernel Reference
Manual (Libraries)' for more details.


@EndNode

@Node "List functions" "beginner.guide/List functions"
@Next "Complex types"
@Prev "Lists and E-lists"
@Toc "LIST and STRING Types"

List functions
--------------

   There are a number of list functions which are very similar to the
string functions (see @{"String functions" Link "String functions"}).  Remember that E-lists are the
list equivalents of E-strings, i.e., they can be altered and extended
safely without exceeding their bounds.  As with E-strings, E-lists are
downwardly compatible with lists.  Therefore, if a function requires a
list as a parameter you can supply a list or an E-list.  But if a function
requires an E-list you cannot use a list in its place.

@{b}List(@{ub}@{fg shine}maxsize@{fg text}@{b})@{ub} 
     Allocates memory for an E-list of maximum size @{fg shine}maxsize@{fg text} and returns
     a pointer to the list data.  It is used to make space for a new
     E-list, like a @{b}LIST@{ub} declaration does.  The following code fragments
     are (as with @{b}String@{ub}) practically equivalent:

            DEF lt[46]:LIST
          
            DEF lt:PTR TO LONG
            lt:=List(46)

     Remember that you need to check that the return value from @{b}List@{ub} is
     not @{b}NIL@{ub} before you use it as an E-list.  Like @{b}String@{ub}, the memory
     allocated using @{b}List@{ub} is deallocated using @{b}DisposeLink@{ub} (see
     @{"System support functions" Link "System support functions"}).

@{b}ListCmp(@{ub}@{fg shine}list1@{fg text}@{b},@{ub}@{fg shine}list2@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b}=ALL)@{ub} 
     Compares @{fg shine}list1@{fg text} with @{fg shine}list2@{fg text} (they can both be normal or E-lists).
     Works just like @{b}StrCmp@{ub} does for E-strings, so, for example, the
     following comparisons all return @{b}TRUE@{ub}:

            ListCmp([1,2,3,4],   [1,2,3,4])
            ListCmp([1,2,3,4],   [1,2,3,7], 3)
            ListCmp([1,2,3,4,5], [1,2,3],   3)

@{b}ListCopy(@{ub}@{fg shine}e-list@{fg text}@{b},@{ub}@{fg shine}list@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b}=ALL)@{ub} 
     Works just like @{b}StrCopy@{ub}, and the following example shows how to
     initialise an E-list:

            DEF lt[7]:LIST, x
            x:=4
            ListCopy(lt, [1,2,3,x])

     As with @{b}StrCopy@{ub}, an E-list cannot be over-filled using @{b}ListCopy@{ub}.

@{b}ListAdd(@{ub}@{fg shine}e-list@{fg text}@{b},@{ub}@{fg shine}list@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b}=ALL)@{ub} 
     Works just like @{b}StrAdd@{ub}, so this next code fragment results in the
     E-list @{b}lt@{ub} becoming the E-list version of @{b}[1,2,3,4,5,6,7,8]@{ub}.

            DEF lt[30]:LIST
            ListCopy(lt, [1,2,3,4])
            ListAdd(lt, [5,6,7,8])

@{b}ListLen(@{ub}@{fg shine}list@{fg text}@{b})@{ub} 
     Works just like @{b}StrLen@{ub}, returning the length of @{fg shine}list@{fg text}.  There is no
     E-list specific length function.

@{b}ListMax(@{ub}@{fg shine}e-list@{fg text}@{b})@{ub} 
     Works just like @{b}StrMax@{ub}, returning the maximum length of the @{fg shine}e-list@{fg text}.

@{b}SetList(@{ub}@{fg shine}e-list@{fg text}@{b},@{ub}@{fg shine}length@{fg text}@{b})@{ub} 
     Works just like @{b}SetStr@{ub}, setting the length of @{fg shine}e-list@{fg text} to @{fg shine}length@{fg text}.

@{b}ListItem(@{ub}@{fg shine}list@{fg text}@{b},@{ub}@{fg shine}index@{fg text}@{b})@{ub} 
     Returns the element of @{fg shine}list@{fg text} at @{fg shine}index@{fg text}.  For example, if @{b}lt@{ub} is an
     E-list then @{b}ListItem(lt,n)@{ub} is the same as @{b}lt[n]@{ub}.  This function is
     most useful when the list is not an E-list.  For example, the
     following two code fragments are equivalent:

            WriteF(ListItem(['Fred','Barney','Wilma','Betty'], name))
          
            DEF lt:PTR TO LONG
            lt:=['Fred','Barney','Wilma','Betty']
            WriteF(lt[name])


@EndNode

@Node "Complex types" "beginner.guide/Complex types"
@Next "Typed lists"
@Prev "List functions"
@Toc "LIST and STRING Types"

Complex types
-------------

   In E the @{b}STRING@{ub} and @{b}LIST@{ub} types are called @{fg shine}complex@{fg text} types.  Complex
typed variables can also be created using the @{b}String@{ub} and @{b}List@{ub} functions as
we've seen in the previous sections.


@EndNode

@Node "Typed lists" "beginner.guide/Typed lists"
@Next "Static data"
@Prev "Complex types"
@Toc "LIST and STRING Types"

Typed lists
-----------

   Normal lists contain @{b}LONG@{ub} elements, so you can write initialised arrays
of @{b}LONG@{ub} elements.  What about other kinds of array?  Well, that's what
@{fg shine}typed@{fg text} lists are for.  You specify the type of the elements of a list
using @{b} :@{ub}@{fg shine}type@{fg text}@{b}@{ub} after the closing @{b}]@{ub}.  The allowable types are @{b}CHAR@{ub}, @{b}INT@{ub},
@{b}LONG@{ub} and any object type.  There is a subtle difference between a normal,
@{b}LONG@{ub} list and a typed list (even a @{b}LONG@{ub} typed list): only normal lists can
be used with the list functions (see @{"List functions" Link "List functions"}).  For this reason,
the term `list' tends to refer only to normal lists.

   The following code fragment uses the object @{b}rec@{ub} defined earlier (see
@{"Example object" Link "Example object"}) and gives a couple of examples of typed lists:

       DEF ints:PTR TO INT, objects:PTR TO rec, p:PTR TO CHAR
       ints:=[1,2,3,4]:INT
       p:='fred'
       objects:=[1,2,p,4,
                 300,301,'barney',303]:rec

It is equivalent to:

       DEF ints[4]:ARRAY OF INT, objects[2]:ARRAY OF rec, p:PTR TO CHAR
       ints[0]:=1
       ints[1]:=2
       ints[2]:=3
       ints[3]:=4
       p:='fred'
       objects[0].tag:=1
       objects[0].check:=2
       objects[0].table:=p
       objects[0].data:=4
       objects[1].table:='barney'
       objects[1].tag:=300
       objects[1].data:=303
       objects[1].check:=301

   The last group of assignments to @{b}objects[1]@{ub} have deliberately been
shuffled in order to emphasise that the order of the elements in the
@{i}definition@{ui} of the object @{b}rec@{ub} is significant.  Each of the elements of the
list corresponds to an element in the object, and the order of elements in
the list corresponds to the order in the object definition.  In the
example, the (object) list assignment line was broken after the end of the
first object (the fourth element) to make it a bit more readable.  The
last object in the list need not be completely defined, so, for instance,
the second line of the assignment could have contained only three elements.
This makes an object-typed list slightly different from the corresponding
array of objects, since an array always defines a whole number of objects.
With an object-typed list you must be careful not to access the undefined
elements of a partially defined trailing object.


@EndNode

@Node "Static data" "beginner.guide/Static data"
@Prev "Typed lists"
@Toc "LIST and STRING Types"

Static data
-----------

   String constants (e.g., @{b}fred@{ub}), lists (e.g., @{b}[1,2,3]@{ub}) and typed lists
(e.g., @{b}[1,2,3]:INT@{ub}) are @{fg shine}static@{fg text} data.  This means that the address of the
(initialised) data is fixed when the program is run.  Normally you don't
need to worry about this, but, for instance, if you want to have a series
of lists as initialised arrays you might be tempted to use some kind of
loop:

     PROC main()
       DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
       FOR i:=0 TO 9
         a[i]:=[1, i, i*i]
           /* This assignment is probably not what you want! */
       ENDFOR
       FOR i:=0 TO 9
         p:=a[i]
         WriteF('a[\d] is an array at address \d\n', i, p)
         WriteF('  and the second element is \d\n', p[1])
       ENDFOR
     ENDPROC

The array @{b}a@{ub} is an array of pointers to initialised arrays (which are all
three elements long).  But, as the comment suggests and the program shows,
this probably doesn't do what was intended, since the list is static.
That means the address of the list is fixed, so each element of @{b}a@{ub} gets the
same address (i.e., the same array).  Since @{b}i@{ub} is used in the list the
contents of that part of memory varies slightly as the first @{b}FOR@{ub} loop is
processed.  But after this loop the contents remain fixed, and the second
element of each of the ten arrays is always nine.  This is an example of
the output that will be generated (the @{b}...@{ub} represents a number of similar
lines):

     a[0] is an array at address 4021144
       and the second element is 9
     a[1] is an array at address 4021144
       and the second element is 9
     ...
     a[9] is an array at address 4021144
       and the second element is 9

One solution is to use the dynamic typed-allocation operator @{b}NEW@{ub} (see
@{"NEW and END Operators" Link "NEW and END Operators"}).  Another solution is to use the function @{b}List@{ub} and
copy the normal list into the new E-list using @{b}ListCopy@{ub}:

     PROC main()
       DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
       FOR i:=0 TO 9
         a[i]:=List(3)
         /* Must check that the allocation succeeded before copying */
         IF a[i]<>NIL THEN ListCopy(a[i], [1, i, i*i], ALL)
       ENDFOR
       FOR i:=0 TO 9
         p:=a[i]
         IF p=NIL
           WriteF('Could not allocate memory for a[\d]\n', i)
         ELSE
           WriteF('a[\d] is an array at address \d\n', i, p)
           WriteF('  and the second element is \d\n', p[1])
         ENDIF
       ENDFOR
     ENDPROC

   The problem is not so bad with string constants, since the contents are
fixed.  However, if you alter the contents explicitly, you will need to
take care not to run into the same problem, as this next example shows.

     PROC main()
       DEF i, strings[10]:ARRAY OF LONG, s:PTR TO CHAR
       FOR i:=0 TO 9
         strings[i]:='Hello World\n'
           /* This assignment is probably not what you want! */
       ENDFOR
       s:=strings[4]
       s[5]:="X"
       FOR i:=0 TO 9
         WriteF('strings[\d] is ', i)
         WriteF(strings[i])
       ENDFOR
     ENDPROC

This is an example of the output that will be generated (again, the @{b}...@{ub}
represents a number of similar lines)::

     strings[0] is HelloXWorld
     strings[1] is HelloXWorld
     ...
     strings[9] is HelloXWorld

Again, the solution is to use dynamic allocation.  The functions @{b}String@{ub}
and @{b}StrCopy@{ub} should be used in the same way that @{b}List@{ub} and @{b}ListCopy@{ub} were
used above.


@EndNode

@Node "Linked Lists" "beginner.guide/Linked Lists"
@Prev "LIST and STRING Types"
@Toc "Types"

Linked Lists
============

   E-lists and E-strings have a useful extension: they can be used to make
@{fg shine}linked lists@{fg text}.  These are like the lists we've seen already, except the
list elements do not occupy a contiguous block of memory.  Instead, each
element has an extra piece of data: a pointer to the next element in the
list.  This means that each element can be anywhere in memory.  (Normally,
the next element of a list is in the next position in memory.) The end of
a linked list has been reached when the pointer to the next element is the
special value @{b}NIL@{ub} (a constant).  You need to be very careful to check that
the pointer is not @{b}NIL@{ub} because if you dereference a @{b}NIL@{ub} pointer the
program will most definitely crash.

   The elements of a linked list are E-lists or E-strings (i.e., the
elements are complex typed).  So, you can link E-lists to get a `linked
list of E-lists' (or, more simply, a `list of lists').  Similarly, linking
E-strings gives `linked list of E-strings', or a `list of strings'.  You
don't have to stick to these two kinds of linked lists, though: you can
use a mixture of E-lists and E-strings in the same linked list.  To link
one complex typed element to another you use the @{b}Link@{ub} function and to find
subsequent elements in a linked list you use the @{b}Next@{ub} or @{b}Forward@{ub} functions.

@{b}Link(@{ub}@{fg shine}complex1@{fg text}@{b},@{ub}@{fg shine}complex2@{fg text}@{b})@{ub} 
     Links @{fg shine}complex1@{fg text} to @{fg shine}complex2@{fg text}.  Both must be an E-list or an
     E-string, with the exception that @{fg shine}complex2@{fg text} can be the special
     constant @{b}NIL@{ub} to indicate that @{fg shine}complex1@{fg text} is the end of the linked
     list.  The value @{fg shine}complex1@{fg text} is returned by the function, which isn't
     always useful so, usually, calls to @{b}Link@{ub} will be used as statements
     rather than functions.  The effect of @{b}Link@{ub} is that @{fg shine}complex1@{fg text} will
     point to @{fg shine}complex2@{fg text} as the next element in the linked list (so
     @{fg shine}complex1@{fg text} is the @{fg shine}head@{fg text} of the list, and @{fg shine}complex2@{fg text} is the @{fg shine}tail@{fg text}).
     For both E-lists and E-strings the pointer to the next element is
     initially @{b}NIL@{ub}, so you will only need to use @{b}Link@{ub} with a @{b}NIL@{ub} parameter
     when you want to make a linked list shorter (by losing the tail).

@{b}Next(@{ub}@{fg shine}complex@{fg text}@{b})@{ub} 
     Returns the pointer to the next element in the linked list.  This may
     be the special constant @{b}NIL@{ub} if @{fg shine}complex@{fg text} is the last element in the
     linked list.  Be careful to check that the value isn't @{b}NIL@{ub} before you
     dereference it!  Follow the comments in the example below:

            DEF s[23]:STRING, t[7]:STRING, lt[41]:LIST, lnk
            /* The next two lines set up the linked list "lnk" */
            lnk:=Link(lt,t)  /* lnk list starts at lt and is lt->t    */
            lnk:=Link(s,lt)  /*   Now it starts at s  and is s->lt->t */
            /* The next three lines follow the links in "lnk"  */
            lnk:=Next(lnk)   /*   Now it starts at lt and is lt->t    */
            lnk:=Next(lnk)   /*   Now it starts at t  and is t        */
            lnk:=Next(lnk)   /* Now lnk is NIL so the list has ended  */

     You may safely call @{b}Next@{ub} with a @{b}NIL@{ub} parameter, and in this case it
     will return @{b}NIL@{ub}.

@{b}Forward(@{ub}@{fg shine}complex@{fg text}@{b},@{ub}@{fg shine}expression@{fg text}@{b})@{ub} 
     Returns a pointer to the element which is @{fg shine}expression@{fg text} number of
     links down the linked list @{fg shine}complex@{fg text}.  If @{fg shine}expression@{fg text} represents the
     value one a pointer to the next element is returned (just like using
     @{b}Next@{ub}).  If it's two a pointer to the element after that is returned.

     If @{fg shine}expression@{fg text} represents a number which is greater than the number
     of links in the list the special value @{b}NIL@{ub} is returned.

   Since the link in a linked list is a pointer to the next element you
can only look through the list from beginning to end.  Technically this is
a @{fg shine}singly@{fg text} linked list (a @{fg shine}doubly@{fg text} linked list would also have a pointer
to the previous element in the list, enabling backwards searching through
the list).

   Linked lists are useful for building lists that can grow quite large.
This is because it's much better to have lots of small bits of memory than
a large lump.  However, you only need to worry about these things when
you're playing with quite big lists (as a rough guide, ones with over
100,000 elements are big!).


@EndNode

@Node "More About Statements and Expressions" "beginner.guide/More About Statements and Expressions"
@Next "E Built-In Constants Variables and Functions"
@Prev "Types"
@Toc "Main"

More About Statements and Expressions
*************************************

   This chapter details various E statements and expressions that were not
covered in Part One.  It also completes some of the partial descriptions
given in Part One.


 @{" Turning an Expression into a Statement " Link "Turning an Expression into a Statement"} 
 @{" Initialised Declarations " Link "Initialised Declarations"} 
 @{" Assignments " Link "Assignments"} 
 @{" More Expressions " Link "More Expressions"} 
 @{" More Statements " Link "More Statements"} 
 @{" Unification " Link "Unification"} 
 @{" Quoted Expressions " Link "Quoted Expressions"} 
 @{" Assembly Statements " Link "Assembly Statements"} 


@EndNode

@Node "Turning an Expression into a Statement" "beginner.guide/Turning an Expression into a Statement"
@Next "Initialised Declarations"
@Toc "More About Statements and Expressions"

Turning an Expression into a Statement
======================================

   The @{b}VOID@{ub} operator converts an expression to a statement.  It does this
by evaluating the expression and then throwing the result away.  This may
not seem very useful, but in fact we've done it a lot already.  We didn't
use @{b}VOID@{ub} explicitly because E does this automatically if it finds an
expression where it was expecting a statement (normally when it is on a
line by itself).  Some of the expressions we've turned into statements
were the procedure calls (to @{b}WriteF@{ub} and @{b}fred@{ub}) and the use of @{b}++@{ub}.  Remember
that all procedure calls denote values because they're really functions
that, by default, return zero (see @{"Functions" Link "Functions"}).

   For example, the following code fragments are equivalent:

       VOID WriteF('Hello world\n')
       VOID x++
     
       WriteF('Hello world\n')
       x++

Since E automatically uses @{b}VOID@{ub} it's a bit of a waste of time writing it
in, although there may be occasions where you want to use it to make this
voiding process more explicit (to the reader).  The important thing is the
fact that expressions can validly be used as statements in E.


@EndNode

@Node "Initialised Declarations" "beginner.guide/Initialised Declarations"
@Next "Assignments"
@Prev "Turning an Expression into a Statement"
@Toc "More About Statements and Expressions"

Initialised Declarations
========================

   Some variables can be initialised using constants in their declarations.
The variables you cannot initialise in this way are array and complex type
variables (and procedure parameters, obviously).  All the other kinds can
be initialised, whether they are local or global.  An @{fg shine}initialised
declaration@{fg text} looks very much like a constant definition, with the value
following the variable name and a @{b}=@{ub} character joining them.  The following
example illustrates initialised declarations:

     SET ENGLISH, FRENCH, GERMAN, JAPANESE, RUSSIAN
     
     CONST FREDLANGS=ENGLISH OR FRENCH OR GERMAN
     
     DEF fredspeak=FREDLANGS,
         p=NIL:PTR TO LONG, q=0:PTR TO rec
     
     PROC fred()
       DEF x=1, y=88
       /* Rest of procedure */
     ENDPROC

Notice how the constant @{b}FREDLANGS@{ub} needs to be defined in order to
initialise the declaration of @{b}fredspeak@{ub} to something mildly complicated.
Also, notice the initialisation of the pointers @{b}p@{ub} and @{b}q@{ub}, and the position
of the type information.

   Of course, if you want to initialise variables with anything more
complicated than a constant you can use assignments at the start of the
code.  Generally, you should always initialise your variables (using
either method) so that they are guaranteed to have a sensible value when
you use them.  Using the value of a variable that you haven't initialised
in some way will probably get you in to a lot of trouble, because the
value will just be some random value that happened to be in the memory
used by the variable.  There are rules for how E initialises some kinds of
variables (see the `Reference Manual', but it's wise to explicitly
initialise even those, as (strangely enough!) this will make your program
more readable.


@EndNode

@Node "Assignments" "beginner.guide/Assignments"
@Next "More Expressions"
@Prev "Initialised Declarations"
@Toc "More About Statements and Expressions"

Assignments
===========

   We've already seen some assignments--these were assignment statements.
Assignment expressions are similar except (as you've guessed) they can be
used in expressions.  This is because they return the value on the
right-hand side of the assignment as well as performing the assignment.
This is useful for efficiently checking that the value that's been
assigned is sensible.  For instance, the following code fragments are
equivalent, but the first uses an assignment expression instead of a
normal assignment statement.

       IF (x:=y*z)=0
         WriteF('Error: y*z is zero (and x is zero)\n')
       ELSE
         WriteF('OK: y*z is not zero (and x is y*z)\n')
       ENDIF
     
       x:=y*z
       IF x=0
         WriteF('Error: y*z is zero (and x is zero)\n')
       ELSE
         WriteF('OK: y*z is not zero (and x is y*z)\n')
       ENDIF

You can easily tell the assignment expression: it's in parentheses and not
on a line by itself.  Notice the use of parentheses to group the
assignment expression.  Technically, the assignment operator has a very
low precedence.  Less technically, it will take as much as it can of the
right-hand side to form the value to be assigned, so you need to use
parentheses to stop @{b}x@{ub} getting the value @{b}((y*z)=0)@{ub} (which will be @{b}TRUE@{ub} or
@{b}FALSE@{ub}, i.e., -1 or zero).

   Assignment expressions, however, don't allow as rich a left-hand side
as assignment statements.  The only thing allowed on the left-hand side of
an assignment expression is a variable name, whereas the statement form
allows:

       @{fg shine}var@{fg text}
       @{fg shine}var@{fg text} [ @{fg shine}expression@{fg text} ]
       @{fg shine}var@{fg text} . @{fg shine}obj_element_name@{fg text}
       ^ @{fg shine}var@{fg text}

(With as many repetitions of object element selection and/or array
indexing as the elements' types allow.) Each of these may end with @{b}++@{ub} or
@{b}--@{ub}.  Therefore, the following are all valid assignments (the last
three use assignment expressions):

       x:=2
       x--:=1
       x[a*b]:=rubble
       x.apple++:=3
       x[22].apple:=y*z
       x[].banana.basket[6]:=3+full(9)
       x[].pear--:=fred(2,4)
     
       x.pear:=(y:=2)
       x[y*z].table[1].orange:=(IF (y:=z)=2 THEN 77 ELSE 33)
       WriteF('x is now \d\n', x:=1+(y:=(z:=fred(3,5)/2)*8))

You may be wondering what the @{b}++@{ub} or @{b}--@{ub} affect.  Well, it's very simple:
they only affect the @{fg shine}var@{fg text}, which is @{b}x@{ub} in all of the examples above.
Notice that @{b}x[].pear--@{ub} is the same as @{b}x.pear--@{ub}, for the same reasons
mentioned earlier (see @{"Element selection and element types" Link "Element selection and element types"}).


@EndNode

@Node "More Expressions" "beginner.guide/More Expressions"
@Next "More Statements"
@Prev "Assignments"
@Toc "More About Statements and Expressions"

More Expressions
================

   This section discusses side-effects, details two new operators (@{b}BUT@{ub} and
@{b}SIZEOF@{ub}) and completes the description of the @{b}AND@{ub} and @{b}OR@{ub} operators.


 @{" Side-effects " Link "Side-effects"} 
 @{" BUT expression " Link "BUT expression"} 
 @{" Bitwise AND and OR " Link "Bitwise AND and OR"} 
 @{" SIZEOF expression " Link "SIZEOF expression"} 


@EndNode

@Node "Side-effects" "beginner.guide/Side-effects"
@Next "BUT expression"
@Toc "More Expressions"

Side-effects
------------

   If evaluating an expression causes the contents of variables to change
then that expression is said to have @{fg shine}side-effects@{fg text}.  An assignment
expression is a simple example of an expression with side-effects.  Less
obvious ones involve function calls with pointers to variables.
Generally, expressions with side-effects should be avoided unless it is
really obvious what is happening.  This is because it can be difficult to
find problems with your program's code if subtleties are buried in
complicated expressions.  On the other hand, side-effecting expressions
are concise and often very elegant.  They are also useful for @{i}obfuscating@{ui}
your code (i.e., making it difficult to understand--a form of copy
protection!).


@EndNode

@Node "BUT expression" "beginner.guide/BUT expression"
@Next "Bitwise AND and OR"
@Prev "Side-effects"
@Toc "More Expressions"

@{b}BUT@{ub} expression
--------------

   @{b}BUT@{ub} is used to sequence two expressions.  @{b}@{ub}@{fg shine}exp1@{fg text}@{b} BUT @{ub}@{fg shine}exp2@{fg text}@{b}@{ub} evaluates
@{fg shine}exp1@{fg text}, and then evaluates and returns the value of @{fg shine}exp2@{fg text}.  This may not
seem very useful at first sight, but if the first expression is an
assignment it allows for a more general assignment expression.  For
example, the following code fragments are equivalent:

       fred((x:=12*3) BUT x+y)
     
       x:=12*3
       fred(x+y)

Notice that parentheses need to be used around the assignment expression
(in the first fragment) for the reasons given earlier (see @{"Assignments" Link "Assignments"}).


@EndNode

@Node "Bitwise AND and OR" "beginner.guide/Bitwise AND and OR"
@Next "SIZEOF expression"
@Prev "BUT expression"
@Toc "More Expressions"

Bitwise @{b}AND@{ub} and @{b}OR@{ub}
------------------

   As hinted in the earlier chapters, the operators @{b}AND@{ub} and @{b}OR@{ub} are not
simply logical operators.  In fact, they are both bit-wise operators,
where a @{fg shine}bit@{fg text} is a binary digit (i.e., the zeroes or ones in the binary
form of a number).  So, to see how they work we should look at what
happens to zeroes and ones:

      x  y   x OR y  x AND y
     ------------------------
      1  1     1        1
      1  0     1        0
      0  1     1        0
      0  0     0        0

   Now, when you @{b}AND@{ub} or @{b}OR@{ub} two numbers the corresponding bits (binary
digits) of the numbers are compared individually, according to the above
table.  So if @{b}x@{ub} were @{b}%0111010@{ub} and @{b}y@{ub} were @{b}%1010010@{ub} then @{b}x AND y@{ub} would be
@{b}%0010010@{ub} and @{b}x OR y@{ub} would be @{b}%1111010@{ub}:

             %0111010        %0111010
           AND             OR
             %1010010        %1010010
              -------         -------
             %0010010        %1111010

The numbers (in binary form) are lined up above each other, just like you
do additions with normal numbers (i.e., starting with the right-hand
digits, and maybe padding with zeroes on the left-hand side).  The two
bits in each column are @{b}AND@{ub}-ed or @{b}OR@{ub}-ed to give the result below the line.

   So, how does this work for @{b}TRUE@{ub} and @{b}FALSE@{ub} and logic operations?  Well,
@{b}FALSE@{ub} is the number zero, so all the bits of @{b}FALSE@{ub} are zeroes, and @{b}TRUE@{ub} is
-1, which is has all 32 bits as ones (these numbers are @{b}LONG@{ub} so they are
32-bit quantities).  So @{b}AND@{ub}-ing and @{b}OR@{ub}-ing these values always gives
numbers which have all zero bits (i.e., @{b}FALSE@{ub}) or all one bits (i.e.,
@{b}TRUE@{ub}), as appropriate.  It's only when you start mixing numbers that
aren't zero or -1 that you can muck up the logic.  The non-zero numbers
one and four are (by themselves) considered to be @{b}TRUE@{ub}, but @{b}4 AND 1@{ub} is
@{b}%100 AND %001@{ub} which is zero (i.e., @{b}FALSE@{ub}).  So when you use @{b}AND@{ub} as the
logical operator it's not strictly true that all non-zero numbers
represent @{b}TRUE@{ub}.  @{b}OR@{ub} does not give such problems so all non-zero numbers
are treated as @{b}TRUE@{ub}.  Run this example to see why you should be careful:

     PROC main()
       test(TRUE,          'TRUE\t\t')
       test(FALSE,         'FALSE\t\t')
       test(1,             '1\t\t')
       test(4,             '4\t\t')
       test(TRUE OR TRUE,  'TRUE OR TRUE\t')
       test(TRUE AND TRUE, 'TRUE AND TRUE\t')
       test(1 OR 4,        '1 OR 4\t\t')
       test(1 AND 4,       '1 AND 4\t\t')
     ENDPROC
     
     PROC test(x, title)
       WriteF(title)
       WriteF(IF x THEN ' is TRUE\n' ELSE ' is FALSE\n')
     ENDPROC

Here's the output that should be generated:

     TRUE             is TRUE
     FALSE            is FALSE
     1                is TRUE
     4                is TRUE
     TRUE OR TRUE     is TRUE
     TRUE AND TRUE    is TRUE
     1 OR 4           is TRUE
     1 AND 4          is FALSE

   So, @{b}AND@{ub} and @{b}OR@{ub} are primarily bit-wise operators, and they can be used
as logical operators under most circumstances, with zero representing
false and all other numbers representing true.  Care must be taken when
using @{b}AND@{ub} with some pairs of non-zero numbers, since the bit-wise @{b}AND@{ub} of
such numbers does not always give a non-zero (or true) result.


@EndNode

@Node "SIZEOF expression" "beginner.guide/SIZEOF expression"
@Prev "Bitwise AND and OR"
@Toc "More Expressions"

@{b}SIZEOF@{ub} expression
-----------------

   @{b}SIZEOF@{ub} returns the size, in bytes, of an object or a built-in type
(like @{b}LONG@{ub}).  This can be useful for determining storage requirements.
For instance, the following code fragment prints the size of the object
@{b}rec@{ub}:

     OBJECT rec
       tag, check
       table[8]:ARRAY
       data:LONG
     ENDOBJECT
     
     PROC main()
       WriteF('Size of rec object is \d bytes\n', SIZEOF rec)
     ENDPROC

   You may think that @{b}SIZEOF@{ub} is unnecessary because you can easily
calculate the size of an object just by looking at the sizes of the
elements.  Whilst this is generally true (it was for the @{b}rec@{ub} object),
there is one thing to be careful about: alignment.  This means that @{b}ARRAY@{ub},
@{b}INT@{ub}, @{b}LONG@{ub} and object typed elements must start at an even memory address.
Normally this isn't a problem, but if you have an odd number of
consecutive @{b}CHAR@{ub} typed elements or an odd sized @{b}ARRAY OF CHAR@{ub}, an extra,
@{fg shine}pad@{fg text} byte is introduced into the object so that the following element is
aligned properly.  This pad byte can be considered part of an @{b}ARRAY OF
CHAR@{ub}, so in effect this means array sizes are rounded up to the
nearest even number.  Otherwise, pad bytes are just an unusable part of an
object, and their presence means the object size is not quite what you'd
expect.  Try the following program:

     OBJECT rec2
       tag, check
       table[7]:ARRAY
       data:LONG
     ENDOBJECT
     
     PROC main()
       WriteF('Size of rec2 object is \d bytes\n', SIZEOF rec2)
     ENDPROC

The only difference between the @{b}rec@{ub} and @{b}rec2@{ub} objects is that the array
size is seven in @{b}rec2@{ub}.  If you run the program you'll see that the size of
the object has not changed.  We might just as well have declared the @{b}table@{ub}
element to be a slightly bigger array (i.e., have eight elements).


@EndNode

@Node "More Statements" "beginner.guide/More Statements"
@Next "Unification"
@Prev "More Expressions"
@Toc "More About Statements and Expressions"

More Statements
===============

   This section details five new statements (@{b}INC@{ub}, @{b}DEC@{ub}, @{b}JUMP@{ub}, @{b}EXIT@{ub} and
@{b}LOOP@{ub}) and describes the use of labelling.


 @{" INC and DEC statements " Link "INC and DEC statements"} 
 @{" Labelling and the JUMP statement " Link "Labelling and the JUMP statement"} 
 @{" EXIT statement " Link "EXIT statement"} 
 @{" LOOP block " Link "LOOP block"} 


@EndNode

@Node "INC and DEC statements" "beginner.guide/INC and DEC statements"
@Next "Labelling and the JUMP statement"
@Toc "More Statements"

@{b}INC@{ub} and @{b}DEC@{ub} statements
----------------------

   @{b}INC x@{ub} is the same as the statement @{b}x:=x+1@{ub}.  However, because it doesn't
do an addition it's a bit more efficient.  Similarly, @{b}DEC x@{ub} is the same as
@{b}x:=x-1@{ub}.

   The observant reader may think that @{b}INC@{ub} and @{b}DEC@{ub} are the same as @{b}++@{ub} and
@{b}--@{ub}.  But there's one important difference: @{b}INC x@{ub} always increases @{b}x@{ub} by
one, whereas @{b}x++@{ub} may increase @{b}x@{ub} by more than one depending on the type to
which @{b}x@{ub} points.  For example, if @{b}x@{ub} were a pointer to @{b}INT@{ub} then @{b}x++@{ub} would
increase @{b}x@{ub} by two (@{b}INT@{ub} is 16-bit, which is two bytes).


@EndNode

@Node "Labelling and the JUMP statement" "beginner.guide/Labelling and the JUMP statement"
@Next "EXIT statement"
@Prev "INC and DEC statements"
@Toc "More Statements"

Labelling and the @{b}JUMP@{ub} statement
--------------------------------

   A @{fg shine}label@{fg text} names a position in a program, and these names are global
(they can be used in any procedure).  The most common use of label is with
the @{b}JUMP@{ub} statement, but you can also use labels to mark the position of
some data (see @{"Assembly Statements" Link "Assembly Statements"}).  To define a label you write a name
followed by a colon immediately before the position you want to mark.
This must be just before the beginning of a statement, either on the
previous line (by itself) or the start of the same line.

   The @{b}JUMP@{ub} statement makes execution continue from the position marked by
a label.  This position must be in the same procedure, but it can be, for
instance, outside of a loop (and the @{b}JUMP@{ub} will then have terminated that
loop).  For example, the following code fragments are equivalent:

       x:=1
       y:=2
       JUMP rubble
       x:=9999
       y:=1234
     rubble:
       z:=88
     
       x:=1
       y:=2
       z:=88

As you can see the @{b}JUMP@{ub} statement has caused the second group of
assignments to @{b}x@{ub} and @{b}y@{ub} to be skipped.  A more useful example uses @{b}JUMP@{ub} to
help terminate a loop:

       x:=1
       y:=2
       WHILE x<10
         IF y<10
           WriteF('x is \d, y is \d\n', x, y)
         ELSE
           JUMP end
         ENDIF
         x:=x+2
         y:=y+2
       ENDWHILE
     end:
       WriteF('Finished!\n')

This loop terminates if @{b}x@{ub} is not less than ten (the @{b}WHILE@{ub} check), or if @{b}y@{ub}
is not less than ten (the @{b}JUMP@{ub} in the @{b}IF@{ub} block).  This may seem pretty
familiar, because it's practically the same as an example earlier (see
@{"WHILE loop" Link "WHILE loop"}).  In fact, it's equivalent to:

       x:=1
       y:=2
       WHILE (x<10) AND (y<10)
         WriteF('x is \d, y is \d\n', x, y)
         x:=x+2
         y:=y+2
       ENDWHILE
       WriteF('Finished!\n')


@EndNode

@Node "EXIT statement" "beginner.guide/EXIT statement"
@Next "LOOP block"
@Prev "Labelling and the JUMP statement"
@Toc "More Statements"

@{b}EXIT@{ub} statement
--------------

   As noted above, you can use the @{b}JUMP@{ub} statement and labelling to break
out of a loop prematurely.  However, a much nicer mechanism exists for
@{b}WHILE@{ub} and @{b}FOR@{ub} loops: the @{b}EXIT@{ub} statement.  This statement will terminate
the closest one of these loops (of which it is part) if the supplied
expression evaluates to true (i.e., a non-zero value).  Any loop using
@{b}EXIT@{ub} can be re-written without it, but sometimes at the expense of
readability.

   The following fragments of code are equivalent:

       FOR x:=1 TO 10
         y:=f(x)
       EXIT y=-1
         WriteF('x=\d, f(x)=\d\n', x, y)
       ENDFOR
     
       FOR x:=1 TO 10
         y:=f(x)
         IF y=-1 THEN JUMP end
         WriteF('x=\d, f(x)=\d\n', x, y)
       ENDFOR
     end:

This example shows a situation which is arguably more readable using
something like @{b}EXIT@{ub}.  It can be rewritten using a @{b}WHILE@{ub} loop, as below,
but the code is a bit less clear.

       going:=TRUE
       x:=1
       WHILE going AND (x<=10)
         y:=f(x)
         IF y=-1
           going:=FALSE
         ELSE
           WriteF('x=\d, f(x)=\d\n', x, y)
           INC x
         ENDIF
       ENDWHILE


@EndNode

@Node "LOOP block" "beginner.guide/LOOP block"
@Prev "EXIT statement"
@Toc "More Statements"

@{b}LOOP@{ub} block
----------

   A @{b}LOOP@{ub} block is a multi-line statement.  It's the general form of loops
like the @{b}WHILE@{ub} loop, and it builds a loop with no check.  So, this kind of
loop would normally never end.  However, as we now know, you can terminate
a @{b}LOOP@{ub} block using the @{b}JUMP@{ub} statement.  As an example, the following two
code fragments are equivalent:

       x:=0
       LOOP
         IF x<100
           WriteF('x is \d\n', x++)
         ELSE
           JUMP end
         ENDIF
       ENDLOOP
     end:
       WriteF('Finished\n')
     
       x:=0
       WHILE x<100
         WriteF('x is \d\n', x++)
       ENDWHILE
       WriteF('Finished\n')


@EndNode

@Node "Unification" "beginner.guide/Unification"
@Next "Quoted Expressions"
@Prev "More Statements"
@Toc "More About Statements and Expressions"

Unification
===========

   In E, @{fg shine}unification@{fg text} is a way of doing complicated, conditional
assignments.  It may also be referred to as @{fg shine}pattern matching@{fg text} because
that is what it does: it matches patterns and tries to fits values to the
variables mentioned in those patterns.  The result of a unification is
true or false, depending on whether the pattern was successfully matched.

   The basic form of a unification expression is:

       @{fg shine}expression@{fg text} <=> @{fg shine}pattern@{fg text}

The only things that can be used in a pattern are constants and variable
names, and lists of patterns.  (Strictly speaking, lisp-cells are also
allowed, but this variant of unification is beyond the scope of this
Guide.) The @{fg shine}pattern@{fg text} is matched against the @{fg shine}expression@{fg text} as follows:

   @{b}*@{ub} If @{fg shine}pattern@{fg text} is a constant then the match succeeds only if
     @{fg shine}expression@{fg text} evaluates to the same value.  So, the simple
     unification expression @{b}x<=>1@{ub} is similar to an equality check @{b}x=1@{ub}.

   @{b}*@{ub} If @{fg shine}pattern@{fg text} is a variable name then the match is successful and the
     variable is assigned the value of @{fg shine}expression@{fg text}.  So, the simple
     unification expression @{b}1<=>x@{ub} is similar to an assignment @{b}x:=1@{ub}.

   @{b}*@{ub} If @{fg shine}pattern@{fg text} is a list then @{fg shine}expression@{fg text} is assumed to be a list, and
     each element of @{fg shine}pattern@{fg text} is taken to be a pattern to be
     (recursively) matched against the corresponding element (by index) of
     the @{fg shine}expression@{fg text} list.  The match succeeds only if the @{fg shine}pattern@{fg text} list
     and the @{fg shine}expression@{fg text} list are the same length and all the elements
     match.  (It is a serious programming error if @{fg shine}pattern@{fg text} is a list but
     @{fg shine}expression@{fg text} does not represent a list.  In this case, strange things
     may happen and the program may crash.)

So, the things in @{fg shine}pattern@{fg text} that control whether a match succeeds are the
constants and the lists.

   If a match succeeds then all variables mentioned in the @{fg shine}pattern@{fg text} will
be assigned the appropriate values.  However, if a match fails you should
consider all variables involved in the pattern to have undefined values
(so you may need to initialise them to safely their values again).  This
is because the actual way that unification is implemented may not follow
the rules above in the obvious way, but will have the same effect in the
successful case and will affect only the variables mentioned in the
pattern if the match fails.

   For example, the following program shows a couple of simple unification
expressions in use:

     PROC main()
       DEF x, lt
       x:=0
       WriteF('x is \d\n', x)
       lt:=[9,-1,7,4]
     
       /* The next line uses unification */
       IF lt <=> [9,-1,x,4]
         WriteF('First match succeeded\n')
         WriteF('1) x is now \d\n', x)
       ELSE
         WriteF('First match failed\n')
         /* To be safe, reset x */
         x:=0
       ENDIF
     
       /* The next line uses unification */
       IF lt <=> [1,x,6,4]
         WriteF('Second match succeeded\n')
         WriteF('2) x is now \d\n', x)
       ELSE
         WriteF('Second match failed\n')
         /* To be safe, reset x */
         x:=0
       ENDIF
     ENDPROC

The first match will succeed in this example, and there will be a
side-effect of assigning seven to @{b}x@{ub}.  The second match will not succeed
because, for instance, the first element of @{b}lt@{ub} is not one.

   We can rewrite the above example without using the unification operator
(to show why unification is so useful).  This code follows the rules in
one particular way, so is not guaranteed to have the same effect as the
unification version if any of the matches fail.

     PROC main()
       DEF x, lt, match
       x:=0
       WriteF('x is \d\n', x)
       lt:=[9,-1,7,4]
     
       /* The next lines mimic: lt <=> [9,-1,x,4] */
       match:=FALSE
       IF ListLen(lt)=4
         IF ListItem(lt, 0)=9
           IF ListItem(lt, 1)=-1
             x:=ListItem(lt,2)
             IF ListItem(lt, 3)=4
               match:=TRUE
             ENDIF
           ENDIF
         ENDIF
       ENDIF
       IF match
         WriteF('First match succeeded\n')
         WriteF('1) x is now \d\n', x)
       ELSE
         WriteF('First match failed\n')
         /* To be safe, reset x */
         x:=0
       ENDIF
     
       /* The next lines mimic: lt <=> [1,x,6,4] */
       match:=FALSE
       IF ListLen(lt)=4
         IF ListItem(lt, 0)=1
           x:=ListItem(lt, 1)
           IF ListItem(lt, 2)=6
             IF ListItem(lt, 3)=4
               match:=TRUE
             ENDIF
           ENDIF
         ENDIF
       ENDIF
       IF match
         WriteF('Second match succeeded\n')
         WriteF('2) x is now \d\n', x)
       ELSE
         WriteF('Second match failed\n')
         /* To be safe, reset x */
         x:=0
       ENDIF
     ENDPROC

   Here's a slightly more complicated example, which shows how you might
use patterns made up of nested lists.  Remember that if the pattern is a
list then the expression to be matched must be a list.  If this is not the
case (e.g., if the expression represents @{b}NIL@{ub}) then your program could
behave strangely or even crash your computer.  A similar, but less
disastrous, problem is if the converse happens: the pattern  is not a list
but the expression to be matched is a list.  In this case the pointer (to
the list) is matched against the pattern constant or assigned to the
pattern variable.

     PROC main()
       DEF x=10, y=-3, p=NIL:PTR TO LONG, lt, i
       WriteF('x is \d, y is \d\n', x, y)
       lt:=[[23,x],y]
     
       /* This basically swaps x and y */
       IF lt <=> [[23,y],x]
         WriteF('First match succeeded\n')
         WriteF('1) Now x is \d, y is \d\n', x, y)
       ELSE
         WriteF('First match failed\n')
         /* To be safe, reset x and y */
         x:=10;  y:=-3
       ENDIF
     
       /* This will make p point to the sub-list of lt */
       IF lt <=> [p,-3]
         WriteF('Second match succeeded\n')
         WriteF('2) p is now $\h (a pointer to a list)\n', p)
         FOR i:=0 TO ListLen(p)-1
           WriteF('   Element \d of the list p is \d\n', i, p[i])
         ENDFOR
       ELSE
         WriteF('First match failed\n')
         /* To be safe, reset p */
         p:=NIL
       ENDIF
     ENDPROC


@EndNode

@Node "Quoted Expressions" "beginner.guide/Quoted Expressions"
@Next "Assembly Statements"
@Prev "Unification"
@Toc "More About Statements and Expressions"

Quoted Expressions
==================

   @{fg shine}Quoted expressions@{fg text} are a powerful feature of the E language, and they
require quite a bit of advanced knowledge.  Basically, you can @{fg shine}quote@{fg text} any
expression by starting it with the back-quote character ` (be careful not
to get it mixed up with the quote character ' which is used for strings).
This quoting action does not evaluate the expression, instead the address
of the code for the expression is returned.  This address can be used just
like any other address, so you can, for instance, store it in a variable
and pass it to procedures.  Of course, at some point you will use the
address to execute the code and get the value of the expression.

   The idea of quoted expressions was borrowed from the functional
programming language Lisp.  Also borrowed were some powerful functions
which combine lists with quoted expressions to give very concise and
readable statements.


 @{" Evaluation " Link "Evaluation"} 
 @{" Quotable expressions " Link "Quotable expressions"} 
 @{" Lists and quoted expressions " Link "Lists and quoted expressions"} 


@EndNode

@Node "Evaluation" "beginner.guide/Evaluation"
@Next "Quotable expressions"
@Toc "Quoted Expressions"

Evaluation
----------

   When you've quoted an expression you have the address of the code which
calculates the value of the expression.  To evaluate the expression you
pass this address to the @{b}Eval@{ub} function.  So now we have a round-about way
of calculating the value of an expression.  (If you have a GB keyboard you
can get the ` character by holding down the ALT key and pressing the '
key, which is in the corner just below the ESC key.  On a US and most
European keyboards it's on the same key but you don't have to press the
ALT key at the same time.)

     PROC main()
       DEF adr, x, y
       x:=0; y:=0
       adr:=`1+(fred(x,1)*8)-y
       x:=2; y:=7
       WriteF('The value is \d\n', Eval(adr))
       x:=1; y:=100
       WriteF('The value is now \d\n', Eval(adr))
     ENDPROC
     
     PROC fred(a,b) RETURN (a+b)*a+20

This is the output that should be generated:

     The value is 202
     The value is now 77

This example shows a quite complicated expression being quoted.  The
address of the expression is stored in the variable @{b}adr@{ub}, and the
expression is evaluated using @{b}Eval@{ub} in the calls to @{b}WriteF@{ub}.  The values of
the variables @{b}x@{ub} and @{b}y@{ub} when the expression is quoted are irrelevant--only
their values each time @{b}Eval@{ub} is used are significant.  Therefore, when @{b}Eval@{ub}
is used in the second call to @{b}WriteF@{ub} the values of @{b}x@{ub} and @{b}y@{ub} have changed so
the resulting value is different.

   Repeatedly evaluating the same expression is the most obvious use of
quoted expressions.  Another common use is when you want to do the same
thing for a variety of different expressions.  For example, if you wanted
to discover the amount of time it takes to calculate the results of
various expressions it would be best to use quoted expressions, something
like this:

     DEF x,y
     
     PROC main()
       x:=999; y:=173
       time(`x+y,     'Addition')
       time(`x*y,     'Multiplication')
       time(`fred(x), 'Procedure call')
     ENDPROC
     
     PROC time(exp, message)
       WriteF(message)
       /* Find current time */
       Eval(exp)
       /* Find new time and calculate difference, t */
       WriteF(': time taken \d\n', t)
     ENDPROC

This is just the outline of a program--it's not complete so don't bother
running it.  The complete version is given as a worked example later (see
@{"Timing Expressions" Link "Timing Expressions"}).


@EndNode

@Node "Quotable expressions" "beginner.guide/Quotable expressions"
@Next "Lists and quoted expressions"
@Prev "Evaluation"
@Toc "Quoted Expressions"

Quotable expressions
--------------------

   There is no restriction on the kinds of expression you can quote,
except that you need to be careful about variable scoping.  If you use
local variables in a quoted expression you can only @{b}Eval@{ub} it within the
same procedure (so the variables are in scope).  However, if you use only
global variables you can @{b}Eval@{ub} it in any procedure.  Therefore, if you are
going to pass a quoted expression to a procedure and do something with it,
you should use only global variables.

   A word of warning: @{b}Eval@{ub} does not check to see if the address it's been
given is really the address of an expression.  You can therefore get in a
real mess if you pass it, say, the address of a variable using @{b}{@{ub}@{fg shine}var@{fg text} @{b} }@{ub}.
You need to check all uses of things like @{b}Eval@{ub} yourself, because the E
compiler lets you write things like @{b}Eval(x+9)@{ub}, where you probably meant to
write @{b}Eval(`x+9)@{ub}.  That's because you might want the address you pass to
@{b}Eval@{ub} to be the result of complicated expressions.  So you may have meant
to pass @{b}x+9@{ub} as the parameter!


@EndNode

@Node "Lists and quoted expressions" "beginner.guide/Lists and quoted expressions"
@Prev "Quotable expressions"
@Toc "Quoted Expressions"

Lists and quoted expressions
----------------------------

   There are several E built-in functions which use lists and quoted
expressions in powerful ways.  These functions are similar to functional
programming constructs and, basically, they allow for very readable code,
which otherwise would require iterative algorithms (i.e., loops).

@{b}MapList(@{ub}@{fg shine}address@{fg text}@{b},@{ub}@{fg shine}list@{fg text}@{b},@{ub}@{fg shine}e-list@{fg text}@{b},@{ub}@{fg shine}quoted-exp@{fg text}@{b})@{ub} 
     The @{fg shine}address@{fg text} is the address of a variable (e.g., @{b}{x}@{ub}), @{fg shine}list@{fg text} is a
     list or E-list (the source), @{fg shine}e-list@{fg text} is an E-list variable (the
     destination), and @{fg shine}quoted-exp@{fg text} is the address of an expression which
     involves the addressed variable (e.g., @{b}`x+2@{ub}).  The effect of the
     function is to take, in turn, a value from @{fg shine}list@{fg text}, store it at
     @{fg shine}address@{fg text}, evaluate the quoted expression and store the result in the
     destination list.  The resulting list is also returned (for
     convenience).

     For example:

            MapList({y}, [1,2,3,a,99,1+c], lt, `y*y)

     results in @{b}lt@{ub} taking the value:

            [1,4,9,a*a,9801,(1+c)*(1+c)]

     Functional programmers would say that @{b}MapList@{ub} @{fg shine}mapped@{fg text} the function
     (the quoted expression) across the (source) list.

@{b}ForAll(@{ub}@{fg shine}address@{fg text}@{b},@{ub}@{fg shine}list@{fg text}@{b},@{ub}@{fg shine}quoted-exp@{fg text}@{b})@{ub} 
     Works just like @{b}MapList@{ub} except that the resulting list is not stored.
     Instead, @{b}ForAll@{ub} returns @{b}TRUE@{ub} if every element of the resulting list is
     @{b}TRUE@{ub} (i.e., non-zero), and @{b}FALSE@{ub} otherwise.  In this way it
     decides whether the quoted expression is @{b}TRUE@{ub} @{fg shine}for all@{fg text} elements of
     the source list.  For example, the following are @{b}TRUE@{ub}:

            ForAll({x}, [1,2,-13,8,0], `x<10)
            ForAll({x}, [1,2,-13,8,0], `x<=8)
            ForAll({x}, [1,2,-13,8,0], `x>-20)

     and these are @{b}FALSE@{ub}:

            ForAll({x}, [1,2,-13,8,0], `x OR x)
            ForAll({x}, [1,2,-13,8,0], `x=2)
            ForAll({x}, [1,2,-13,8,0], `x<>2)

@{b}Exists(@{ub}@{fg shine}address@{fg text}@{b},@{ub}@{fg shine}list@{fg text}@{b},@{ub}@{fg shine}quoted-exp@{fg text}@{b})@{ub} 
     Works just like @{b}ForAll@{ub} except it returns @{b}TRUE@{ub} if the quoted
     expression is @{b}TRUE@{ub} (i.e., non-zero) for at least one of the source
     list elements and @{b}FALSE@{ub} otherwise.  For example, the following are
     @{b}TRUE@{ub}:

            Exists({x}, [1,2,-13,8,0], `x<10)
            Exists({x}, [1,2,-13,8,0], `x=2)
            Exists({x}, [1,2,-13,8,0], `x>0)

     and these are @{b}FALSE@{ub}:

            Exists({x}, [1,2,-13,8,0], `x<-20)
            Exists({x}, [1,2,-13,8,0], `x=4)
            Exists({x}, [1,2,-13,8,0], `x>8)

@{b}SelectList(@{ub}@{fg shine}address@{fg text}@{b},@{ub}@{fg shine}list@{fg text}@{b},@{ub}@{fg shine}e-list@{fg text}@{b},@{ub}@{fg shine}quoted-exp@{fg text}@{b})@{ub} 
     Works just like @{b}MapList@{ub} except the @{fg shine}quoted-exp@{fg text} is used to decide
     which elements from @{fg shine}list@{fg text} are copied to @{b}e-list@{ub}.  Only the elements
     for which @{fg shine}quoted-exp@{fg text} evaluates to a non-zero (i.e., true) value are
     copied.  The resulting list is also returned (for convenience).

     For example:

            SelectList({y}, [99,6,1,2,7,1,1,6,6], lt, `y>5)

     results in @{b}lt@{ub} taking the value:

            [99,6,7,6,6]


@EndNode

@Node "Assembly Statements" "beginner.guide/Assembly Statements"
@Prev "Quoted Expressions"
@Toc "More About Statements and Expressions"

Assembly Statements
===================

   The E language incorporates an assembler so you can write Assembly
mnemonics as E statements.  You can even write complete Assembly programs
and compile them using the E compiler.  More powerfully, you can use E
variables as part of the mnemonics, so you can really mix Assembly
statements with normal E statements.

   This is not really the place to discuss Assembly programming, so if you
plan to use this feature of E you should get yourself a good book,
preferably on Amiga Assembly.  Remember that the Amiga uses the Motorola
68000 CPU, so you need to learn the Assembly language for that CPU.  More
powerful and newer Amigas use more advanced CPUs (such as the 68020) which
have extra mnemonics.  Programs written using just 68000 CPU mnemonics
will work on all Amigas.

   If you don't know 68000 Assembly language you ought to skip this
section and just bear in mind that E statements you don't recognise are
probably Assembly mnemonics.


 @{" Assembly and the E language " Link "Assembly and the E language"} 
 @{" Static memory " Link "Static memory"} 
 @{" Things to watch out for " Link "Things to watch out for"} 


@EndNode

@Node "Assembly and the E language" "beginner.guide/Assembly and the E language"
@Next "Static memory"
@Toc "Assembly Statements"

Assembly and the E language
---------------------------

   You can reference E variables simply by using them in an operand.
Follow the comments in the next example (the comments are on the same
lines as the Assembly mnemonics, the other lines are normal E statements):

     PROC main()
       DEF x
       x:=1
       MOVE.L x,  D0 /* Copy the value in x to register D0      */
       ADD.L  D0, D0 /* Double the value in D0                  */
       MOVE.L D0, x  /* Copy the value in D0 back to variable x */
       WriteF('x is now \d\n', x)
     ENDPROC

Constants can also be referenced but you need to precede the constant with
a @{b}#@{ub}.

     CONST APPLE=2
     
     PROC main()
       DEF x
       MOVE.L #APPLE, D0 /* Copy the constant APPLE to register D0 */
       ADD.L  D0, D0     /* Double the value in D0                 */
       MOVE.L D0, x      /* Copy the value in D0 to variable x     */
       WriteF('x is now \d\n', x)
     ENDPROC

Labels and procedures can similarly be referenced, but these are
PC-relative so you can only address them in this way.  The following
example illustrates this, but doesn't do anything useful:

     PROC main()
       DEF x
       LEA main(PC), A0 /* Copy the address of main to register A0 */
       MOVE.L A0, x     /* Copy the value in A0 to variable x      */
       WriteF('x is now \d\n', x)
     ENDPROC

You can call Amiga system functions in the same way as you would normally
in Assembly.  You need to load the A6 register with the appropriate
library base, load the other registers with appropriate data and then @{b}JSR@{ub}
to the system routine.  This next example uses the E built-in variable
@{b}intuitionbase@{ub} and the Intuition library routine @{b}DisplayBeep@{ub}.  When you run
it the screen flashes (or, with Workbench 2.1 and above, you might get a
beep or a sampled sound, depending on your Workbench setup).

     PROC main()
       MOVE.L #NIL, A0
       MOVE.L intuitionbase, A6
       JSR DisplayBeep(A6)
     ENDPROC


@EndNode

@Node "Static memory" "beginner.guide/Static memory"
@Next "Things to watch out for"
@Prev "Assembly and the E language"
@Toc "Assembly Statements"

Static memory
-------------

   Assembly programs reserve static memory for things like strings using
@{b}DC@{ub} mnemonics.  However, these aren't real mnemonics.  They are, in
fact, compiler directives and they can vary from compiler to compiler.
The E versions are @{b}LONG@{ub}, @{b}INT@{ub} and @{b}CHAR@{ub} (the type names), which take a list
of values, reserve the appropriate amount of static memory and fill in
this memory with the supplied values.  The @{b}CHAR@{ub} form also allows a list of
characters to be supplied more easily as a string.  In this case, the
string will automatically be aligned to an even memory location, although
you are responsible for null-terminating it.  You can also include a whole
file as static data using @{b}INCBIN@{ub} (and the file named using this statement
must exist when the program is compiled).  To get at the data you mark it
with a label.

   This next example is a bit contrived, but illustrates some static data:

     PROC main()
       DEF x:PTR TO CHAR
       LEA datatable(PC), A0
       MOVE.L A0, x
       WriteF(x)
     ENDPROC
     
     datatable:
       CHAR 'Hello world\n', 0
     moredata:
       LONG 1,5,-999,0;    INT -1,222
       INCBIN 'file.data'; CHAR 0,7,-8

The Assembly stuff to get the label address is not really necessary, so
the example could have been just:

     PROC main()
       WriteF({datatable})
     ENDPROC
     
     datatable:
       CHAR 'Hello world\n', 0


@EndNode

@Node "Things to watch out for" "beginner.guide/Things to watch out for"
@Prev "Static memory"
@Toc "Assembly Statements"

Things to watch out for
-----------------------

   There are a few things to be aware of when using Assembly with E:

   @{b}*@{ub} All mnemonics and registers must be in uppercase, whilst, of course,
     E variables etc., follow the normal E rules.

   @{b}*@{ub} Most standard Assemblers use @{b};@{ub} to mark the rest of the line as a
     comment.  In E you can use @{b}->@{ub} for the same effect, or you can use the
     @{b}/*@{ub} and @{b}*/@{ub} delimiters.

   @{b}*@{ub} Registers A4 and A5 are used internally by E, so should not be messed
     with if you are mixing E and Assembly code.  Other registers might
     also be used, especially if you've used the @{b}REG@{ub} keyword.  Refer to
     the `Reference Manual' for more details.

   @{b}*@{ub} E function calls like @{b}WriteF@{ub} can affect registers.  Refer to the
     `Reference Manual' for more details.


@EndNode

@Node "E Built-In Constants Variables and Functions" "beginner.guide/E Built-In Constants Variables and Functions"
@Next "Modules"
@Prev "More About Statements and Expressions"
@Toc "Main"

E Built-In Constants, Variables and Functions
*********************************************

   This chapter describes the constants, variables and functions which are
built-in to the E language.  You can add more by using modules, but that's
a more advanced topic (see @{"Modules" Link "Modules"}).


 @{" Built-In Constants " Link "Built-In Constants"} 
 @{" Built-In Variables " Link "Built-In Variables"} 
 @{" Built-In Functions " Link "Built-In Functions"} 


@EndNode

@Node "Built-In Constants" "beginner.guide/Built-In Constants"
@Next "Built-In Variables"
@Toc "E Built-In Constants Variables and Functions"

Built-In Constants
==================

   We've already met several built-in constants.  Here's the complete list:

@{b}TRUE@{ub},  @{b}FALSE@{ub}
     The boolean constants.  As numbers, @{b}TRUE@{ub} is -1 and @{b}FALSE@{ub} is zero.

@{b}NIL@{ub}
     The bad pointer value.  Several functions produce this value for a
     pointer if an error occurred.  As a number, @{b}NIL@{ub} is zero.

@{b}ALL@{ub}
     Used with string and list functions to indicate that all the string
     or list is to be used.  As a number, @{b}ALL@{ub} is -1.

@{b}GADGETSIZE@{ub}
     The minimum number of bytes required to hold all the data for one
     gadget.  See @{"Intuition support functions" Link "Intuition support functions"}.

@{b}OLDFILE@{ub},  @{b}NEWFILE@{ub}
     Used with @{b}Open@{ub} to open an old or new file.  See the `AmigaDOS Manual'
     for more details.

@{b}STRLEN@{ub}
     The length of the last string constant used.  Remember that a string
     constant is something between @{b}'@{ub} characters, so, for example, the
     following program prints the string @{b}s@{ub} and then its length:

          PROC main()
            DEF s:PTR TO CHAR, len
            s:='12345678'
            len:=STRLEN
            WriteF(s)
            WriteF('\nis \d characters long\n', len)
          ENDPROC


@EndNode

@Node "Built-In Variables" "beginner.guide/Built-In Variables"
@Next "Built-In Functions"
@Prev "Built-In Constants"
@Toc "E Built-In Constants Variables and Functions"

Built-In Variables
==================

   The following variables are built-in to E and are called @{fg shine}system
variables@{fg text}.  They are global so can be accessed from any procedure.

@{b}arg@{ub}
     This is a string which contains the @{fg shine}command line@{fg text} arguments passed
     your program when it was run (from the Shell or CLI).  For instance,
     if your program were called @{b}fred@{ub} and you ran it like this:

          fred file.txt "a big file" another

     then @{b}arg@{ub} would the string:

          file.txt "a big file" another

     If you have AmigaDOS 2.0 (or greater) you can use the system routine
     @{b}ReadArgs@{ub} to parse the command line in a much more versatile way.
     There is a worked example on argument parsing in Part Three (see
     @{"Argument Parsing" Link "Argument Parsing"}).

@{b}wbmessage@{ub}
     This contains @{b}NIL@{ub} if your program was started from the Shell/CLI,
     otherwise it's a pointer to the Workbench message which contains
     information about the icons selected when you started the program
     from Workbench.  So, if you started the program from Workbench
     @{b}wbmessage@{ub} will not be @{b}NIL@{ub} and it will contain the Workbench
     arguments, but if you started the program from the Shell/CLI
     @{b}wbmessage@{ub} will be @{b}NIL@{ub} and the argments will be in @{b}arg@{ub} (or via
     @{b}ReadArgs@{ub}).  There is a worked example on argument parsing in Part
     Three (see @{"Argument Parsing" Link "Argument Parsing"}).

@{b}stdin@{ub}, @{b}stdout@{ub},  @{b}conout@{ub}
     The @{b}stdin@{ub} and @{b}stdout@{ub} variables contain the standard input and output
     filehandles.  If your program was started from the Shell/CLI they
     will be filehandles on the Shell/CLI window (and @{b}conout@{ub} will be @{b}NIL@{ub}).
     However, if your program was started from Workbench these will both
     be @{b}NIL@{ub}, and in this case the first call to @{b}WriteF@{ub} will open an output
     @{b}CON:@{ub} window and store the file handle for the window in @{b}stdout@{ub} and
     @{b}conout@{ub}.  The file handle stored in @{b}conout@{ub} when the program terminates
     will be closed using @{b}Close@{ub}, so you can set up your own @{b}CON:@{ub} window or
     file for use by the output functions and have it automatically closed.
     See @{"Input and output functions" Link "Input and output functions"}.

@{b}stdrast@{ub}
     The raster port used by E built-in graphics functions such as @{b}Box@{ub} and
     @{b}Plot@{ub}.  This can be changed so that these functions draw on different
     screens etc.  See @{"Graphics functions" Link "Graphics functions"}.

@{b}dosbase@{ub},  @{b}execbase@{ub},  @{b}gfxbase@{ub},  @{b}intuitionbase@{ub}
     These are pointers to the appropriate library base, and are
     initialised by the E startup code, i.e., the Dos, Exec, Graphics and
     Intuition libraries are all opened by E so you don't need to do it
     yourself.  These libraries are also automatically closed by E, so you
     shouldn't close them yourself.  However, you must explicitly open and
     close all other Amiga system libraries that you want to use.  The
     other library base variables are defined in the accompanying module
     (see @{"Modules" Link "Modules"}).  Consult the `Reference Manual' for details about the
     library base variable @{b}mathbase@{ub}.


@EndNode

@Node "Built-In Functions" "beginner.guide/Built-In Functions"
@Prev "Built-In Variables"
@Toc "E Built-In Constants Variables and Functions"

Built-In Functions
==================

   There are many built-in functions in E. We've already seen a lot of
string and list functions, and we've used @{b}WriteF@{ub} for printing.  The
remaining functions are, generally, simplifications of complex Amiga
system functions, or E versions of support functions found in languages
like C and Pascal.

   To understand the graphics and Intuition support functions completely
you really need to get something like the `Rom Kernel Reference Manual
(Libraries)'.  However, if you don't want to do anything too complicated
you can just about get by.


 @{" Input and output functions " Link "Input and output functions"} 
 @{" Intuition support functions " Link "Intuition support functions"} 
 @{" Graphics functions " Link "Graphics functions"} 
 @{" Maths and logic functions " Link "Maths and logic functions"} 
 @{" System support functions " Link "System support functions"} 


@EndNode

@Node "Input and output functions" "beginner.guide/Input and output functions"
@Next "Intuition support functions"
@Toc "Built-In Functions"

Input and output functions
--------------------------

@{b}WriteF(@{ub}@{fg shine}string@{fg text}@{b},@{ub}@{fg shine}param1@{fg text}@{b},@{ub}@{fg shine}param2@{fg text}@{b},...)@{ub} 
     Writes a string to the standard output and returns the number of
     characters written.  If place-holders are used in the string then the
     appropriate number of parameters must be supplied after the string in
     the order they are to be printed as part of the string.  So far we've
     only met the @{b}\d@{ub} place-holder for decimal numbers.  The complete list
     is:

          @{i}Place-Holder@{ui}  @{i}Parameter Type@{ui}   @{i}Prints@{ui}
          -------------------------------------------------
               \c          Number        Character
               \d          Number        Decimal number
               \h          Number        Hexadecimal number
               \s          String        String

     So to print a string you use the @{b}\s@{ub} place-holder in the string and
     supply the string (e.g., a @{b}PTR TO CHAR@{ub}) as a parameter.  Try the
     following program (remember @{b}\a@{ub} prints an apostrophe character):

          PROC main()
            DEF s[30]:STRING
            StrCopy(s, 'Hello world', ALL)
            WriteF('The third element of s is "\c"\n', s[2])
            WriteF('or \d (decimal)\n',                s[2])
            WriteF('or \h (hexadecimal)\n',            s[2])
            WriteF('and s itself is \a\s\a\n',         s)
          ENDPROC

     This is the output it generates:

          The third element of s is "l"
          or 108 (decimal)
          or 6C (hexadecimal)
          and s itself is 'Hello world'

     You can control how the parameter is formatted in the @{b}\d@{ub}, @{b}\h@{ub} and @{b}\s@{ub}
     fields using another collection of special character sequences before
     the place-holder and size specifiers after it.  If no size is
     specified the field will be as big as the data requires.  A fixed
     field size can be specified using @{b} [@{ub}@{fg shine}number@{fg text}@{b}]@{ub} after the place-holder.
     For strings you can also use the size specifier @{b} (@{ub}@{fg shine}min@{fg text}@{b},@{ub}@{fg shine}max@{fg text}@{b})@{ub} which
     specifies the minimum and maximum sizes of the field.  By default the
     data is right justified in the field and the left part of the field
     is filled, if necessary, with spaces.  The following sequences before
     the place-holder can change this:

          @{i}Sequence@{ui}        @{i}Meaning@{ui}
          -----------------------------------
             \l     Left justify in field
             \r     Right justify in field
             \z     Set fill character to "0"

     See how these formatting controls affect this example:

          PROC main()
            DEF s[30]:STRING
            StrCopy(s, 'Hello world', ALL)
            WriteF('The third element of s is "\c"\n', s[2])
            WriteF('or \d[4] (decimal)\n',             s[2])
            WriteF('or \z\h[4] (hexadecimal)\n',       s[2])
            WriteF('\a\s[5]\a are the first five elements of s \n', s)
            WriteF('and s in a very big field  \a\s[20]\a\n',   s)
            WriteF('and s left justified in it \a\l\s[20]\a\n', s)
          ENDPROC

     Here's the output it should generate:

          The third element of s is "l"
          or  108 (decimal)
          or 006C (hexadecimal)
          'Hello' are the first five elements of s
          and s in a very big field  '         Hello world'
          and s left justified in it 'Hello world         '

     @{b}WriteF@{ub} uses the standard output, and this file handle is stored in
     the @{b}stdout@{ub} variable.  If your program is started from Workbench this
     variable will contain @{b}NIL@{ub}.  In this case, the first call to @{b}WriteF@{ub}
     will open a special output window and put the file handle in the
     variables @{b}stdout@{ub} and @{b}conout@{ub}, as outlined above.

@{b}PrintF(@{ub}@{fg shine}string@{fg text}@{b},@{ub}@{fg shine}param1@{fg text}@{b},@{ub}@{fg shine}param2@{fg text}@{b},...)@{ub} 
     @{b}PrintF@{ub} works just like @{b}WriteF@{ub} except it uses the more efficient,
     buffered output routines only available if your Amiga is using
     Kickstart version 37 or greater (i.e., AmigaDOS 2.04 and above).

@{b}StringF(@{ub}@{fg shine}e-string@{fg text}@{b},@{ub}@{fg shine}string@{fg text}@{b},@{ub}@{fg shine}arg1@{fg text}@{b},@{ub}@{fg shine}arg2@{fg text}@{b},...)@{ub} 
     The same as @{b}WriteF@{ub} except that the result is written to @{fg shine}e-string@{fg text}
     instead of being printed.  For example, the following code fragment
     sets @{b}s@{ub} to @{b}00123 is a@{ub} (since the E-string is not long enough for the
     whole string):

            DEF s[10]:STRING
            StringF(s, '\z\d[5] is a number', 123)

@{b}Out(@{ub}@{fg shine}filehandle@{fg text}@{b},@{ub}@{fg shine}char@{fg text}@{b})@{ub} 
     Outputs a single character, @{fg shine}char@{fg text}, to the file or console window
     denoted by @{fg shine}filehandle@{fg text}, and returns -1 to indicate success (so any
     other return value means an error occurred).  For instance,
     @{fg shine}filehandle@{fg text} could be @{b}stdout@{ub}, in which case the character is written
     to the standard output.  (You need to make sure @{b}stdout@{ub} is not @{b}NIL@{ub},
     and you can do this by using a @{b}WriteF('')@{ub} call.)

@{b}Inp(@{ub}@{fg shine}filehandle@{fg text}@{b})@{ub} 
     Reads and returns a single character from @{fg shine}filehandle@{fg text}.  If -1 is
     returned then the end of the file (EOF) was reached, or there was an
     error.

@{b}ReadStr(@{ub}@{fg shine}filehandle@{fg text}@{b},@{ub}@{fg shine}e-string@{fg text}@{b})@{ub} 
     Reads a whole string from @{fg shine}filehandle@{fg text} and returns -1 if EOF was
     reached or an error occurred.  Characters are read up to a linefeed
     or the size of the string, which ever is sooner.  Therefore, the
     resulting string may be only a partial line.  If -1 is returned then
     EOF was reached or an error occurred, and in either case the string
     so far is still valid.  So, you still need to check the string even
     if -1 is returned.  (This will most commonly happen with files that
     do not end with a linefeed.) The string will be empty (i.e., of zero
     length) if nothing more had been read from the file when the error or
     EOF happened.

     This next little program reads continually from its input until an
     error occurs or the user types @{b}quit@{ub}.  It echoes the lines that it
     reads in uppercase.  If you type a line longer than ten characters
     you'll see it reads it in more than one go.  Because of the way
     normal console windows work, you need to type a return before a line
     gets read by the program (but this allows you to edit the line before
     the program sees it).  If the program is started from Workbench then
     @{b}stdin@{ub} would be @{b}NIL@{ub}, so @{b}WriteF('')@{ub} is used to force @{b}stdout@{ub} to be
     valid, and in this case it will be a new console window which can be
     used to accept input!  (To make the compiled program into a Workbench
     program you simply need to create a tool icon for it.  A quick way of
     doing this is to copy an existing tool's icon.)

          PROC main()
            DEF s[10]:STRING, fh
            WriteF('')
            fh:=IF stdin THEN stdin ELSE stdout
            WHILE ReadStr(fh, s)<>-1
              UpperStr(s)
            EXIT StrCmp(s, 'QUIT', ALL)
              WriteF('Read: \a\s\a\n', s)
            ENDWHILE
            WriteF('Finished\n')
          ENDPROC

     There are some worked examples in Part Three (see
     @{"String Handling and I-O" Link "String Handling and I-O"}) which also show how to use @{b}ReadStr@{ub}.

@{b}FileLength(@{ub}@{fg shine}string@{fg text}@{b})@{ub} 
     Returns the length of the file named in @{fg shine}string@{fg text}, or -1 if the file
     doesn't exist or an error occurred.  Notice that you don't need to
     @{b}Open@{ub} the file or have a filehandle, you just supply the filename.
     There is a worked example in Part Three (see @{"String Handling and I-O" Link "String Handling and I-O"})
     which shows how to use this function.

@{b}SetStdIn(@{ub}@{fg shine}filehandle@{fg text}@{b})@{ub} 
     Returns the value of @{b}stdin@{ub} before setting it to @{fg shine}filehandle@{fg text}.
     Therefore, the following code fragments are equivalent:

            oldstdin:=SetStdIn(newstdin)
          
            oldstdin:=stdin
            stdin:=newstdin

@{b}SetStdOut(@{ub}@{fg shine}filehandle@{fg text}@{b})@{ub} 
     Returns the value of @{b}stdout@{ub} before setting it to @{fg shine}filehandle@{fg text}, and is
     otherwise just like @{b}SetStdIn@{ub}.


@EndNode

@Node "Intuition support functions" "beginner.guide/Intuition support functions"
@Next "Graphics functions"
@Prev "Input and output functions"
@Toc "Built-In Functions"

Intuition support functions
---------------------------

   The functions in this section are simplified versions of Amiga system
functions (in the Intuition library, as the title suggests).  To make best
use of them you are probably going to need something like the `Rom Kernel
Reference Manual (Libraries)', especially if you want to understand the
Amiga specific things like IDCMP and raster ports.

   The descriptions given here vary slightly in style from the previous
descriptions.  All function parameters can be expressions which represent
numbers or addresses, as appropriate.  Because many of the functions take
several parameters they have been named (fairly descriptively) so they can
be more easily referenced.

@{b}OpenW(@{ub}@{fg shine}x@{fg text}@{b},@{ub}@{fg shine}y@{fg text}@{b},@{ub}@{fg shine}wid@{fg text}@{b},@{ub}@{fg shine}hgt@{fg text}@{b},@{ub}@{fg shine}idcmp@{fg text}@{b},@{ub}@{fg shine}wflgs@{fg text}@{b},@{ub}@{fg shine}title@{fg text}@{b},@{ub}@{fg shine}scrn@{fg text}@{b},@{ub}@{fg shine}sflgs@{fg text}@{b},@{ub}@{fg shine}gads@{fg text}@{b},@{ub}@{fg shine}tags@{fg text}@{b}=NIL)@{ub} 
     Opens and returns a pointer to a window with the supplied properties.
     If for some reason the window could not be opened @{b}NIL@{ub} is returned.

    @{fg shine}x@{fg text},  @{fg shine}y@{fg text}
          The position on the screen where the window will appear.

    @{fg shine}wid@{fg text},  @{fg shine}hgt@{fg text}
          The width and height of the window.

    @{fg shine}idcmp@{fg text},  @{fg shine}wflgs@{fg text}
          The IDCMP and window specific flags.

    @{fg shine}title@{fg text}
          The window title (a string) which appears on the title bar of
          the window.

    @{fg shine}scrn@{fg text},  @{fg shine}sflgs@{fg text}
          The screen on which the window should open.  If @{fg shine}sflgs@{fg text} is 1 the
          window will be opened on Workbench, and @{fg shine}scrn@{fg text} is ignored (so it
          can be @{b}NIL@{ub}).  If @{fg shine}sflgs@{fg text} is @{b}$F@{ub} (i.e., 15) the window will open
          on the custom screen pointed to by @{fg shine}scrn@{fg text} (which must then be
          valid).  See @{b}OpenS@{ub} to see how to open a custom screen and get a
          screen pointer.

    @{fg shine}gads@{fg text}
          A pointer to a gadget list, or @{b}NIL@{ub} if you don't want any gadgets.
          These are not the standard window gadgets, since they are
          specified using  the window flags.  A gadget list can be created
          using the @{b}Gadget@{ub} function.

    @{fg shine}tags@{fg text}
          A tag-list of other options available under Kickstart version 37
          or greater.  This can normally be omitted since it defaults to
          @{b}NIL@{ub}.  See the `Rom Kernel Reference Manual (Libraries)' for
          details about the available tags and their meanings.

     There's not enough space to describe all the fine details about
     windows and IDCMP (see the `Rom Kernel Reference Manual (Libraries)'
     for complete details), but a brief description in terms of flags
     might be useful.  Here's a small table of common IDCMP flags:

          @{i}IDCMP Flag@{ui}           @{i}Value@{ui}
          --------------------------
          IDCMP_NEWSIZE           $2
          IDCMP_REFRESHWINDOW     $4
          IDCMP_MOUSEBUTTONS      $8
          IDCMP_MOUSEMOVE        $10
          IDCMP_GADGETDOWN       $20
          IDCMP_GADGETUP         $40
          IDCMP_MENUPICK        $100
          IDCMP_CLOSEWINDOW     $200
          IDCMP_RAWKEY          $400
          IDCMP_DISKINSERTED   $8000
          IDCMP_DISKREMOVED   $10000

     Here's a table of useful window flags:

          @{i}Window Flag@{ui}          @{i}Value@{ui}
          --------------------------
          WFLG_SIZEGADGET         $1
          WFLG_DRAGBAR            $2
          WFLG_DEPTHGADGET        $4
          WFLG_CLOSEGADGET        $8
          WFLG_SIZEBRIGHT        $10
          WFLG_SIZEBBOTTOM       $20
          WFLG_SMART_REFRESH       0
          WFLG_SIMPLE_REFRESH    $40
          WFLG_SUPER_BITMAP      $80
          WFLG_BACKDROP         $100
          WFLG_REPORTMOUSE      $200
          WFLG_GIMMEZEROZERO    $400
          WFLG_BORDERLESS       $800
          WFLG_ACTIVATE        $1000

     All these flags are defined in the module @{b}intuition/intuition@{ub}, so if
     you use that module you can use the constants rather than having to
     write the less descriptive value (see @{"Modules" Link "Modules"}).  Of course, you can
     always define your own constants for the values that you use.

     You use the flags by @{b}OR@{ub}-ing the ones you want together, in similar
     way to using sets (see @{"Sets" Link "Sets"}).  However, you should supply only IDCMP
     flags as part of the @{fg shine}idcmp@{fg text} parameter, and you should supply only
     window flags as part of the @{fg shine}wflgs@{fg text} parameter.  So, to get IDCMP
     messages when a disk is inserted and when the close gadget is clicked
     you specify both of the flags @{b}IDCMP_DISKINSERTED@{ub} and
     @{b}IDCMP_CLOSEWINDOW@{ub} for the @{fg shine}idcmp@{fg text} parameter, either by @{b}OR@{ub}-ing the
     constants or (less readably) by using the calculated value @{b}$8200@{ub}.

     Some of the window flags require some of IDCMP flags to be used as
     well, if an effect is to be complete.  For example, if you want your
     window to have a close gadget (a standard window gadget) you need to
     use @{b}WFLG_CLOSEGADGET@{ub} as one of the window flags.  If you want that
     gadget to be useful then you need to get an IDCMP message when the
     gadget is clicked.  You therefore need to use @{b}IDCMP_CLOSEWINDOW@{ub} as
     one of the IDCMP flags.  So the full effect requires both a window
     and an IDCMP flag (a gadget is pretty useless if you can't tell when
     it's been clicked).  The worked example in Part Three illustrates how
     to use these flags in this way (see @{"Gadgets" Link "Gadgets"}).

     If you only want to output text to a window (and maybe do some input
     from a window), it may be better to use a @{fg shine}console@{fg text} window.  These
     provide a text based input and output window, and are opened using
     the Dos library function @{b}Open@{ub} with the appropriate @{b}CON:@{ub} file name.
     See the `AmigaDOS Manual' for more details about console windows.

@{b}CloseW(@{ub}@{fg shine}winptr@{fg text}@{b})@{ub} 
     Closes the window which is pointed to by @{fg shine}winptr@{fg text}.  It's safe to give
     @{b}NIL@{ub} for @{fg shine}winptr@{fg text}, but in this case, of course, no window will be
     closed!  The window pointer is usually a pointer returned by a
     matching call to @{b}OpenW@{ub}.  You @{i}must@{ui} remember to close any windows you
     may have opened before terminating your program.

@{b}OpenS(@{ub}@{fg shine}wid@{fg text}@{b},@{ub}@{fg shine}hgt@{fg text}@{b},@{ub}@{fg shine}depth@{fg text}@{b},@{ub}@{fg shine}scrnres@{fg text}@{b},@{ub}@{fg shine}title@{fg text}@{b},@{ub}@{fg shine}tags@{fg text}@{b}=NIL)@{ub} 
     Opens and returns a pointer to a custom screen with the supplied
     properties.  If for some reason the screen could not be opened @{b}NIL@{ub} is
     returned.

    @{fg shine}wid@{fg text},  @{fg shine}hgt@{fg text}
          The width and height of the screen.

    @{fg shine}depth@{fg text}
          The depth of the screen, i.e., the number of bit-planes.  This
          can be a number in the range 1-8 for AGA machines, or 1-6 for
          pre-AGA machines.  A screen with depth 3 will be able to show 2
          to the power 3 (i.e., 8) different colours, since it will have 2
          to the power 3 different pens (or colour registers) available.
          You can set the colours of pens using the @{b}SetColour@{ub} function.

    @{fg shine}scrnres@{fg text}
          The screen resolution flags.

    @{fg shine}title@{fg text}
          The screen title (a string) which appears on the title bar of
          the screen.

    @{fg shine}tags@{fg text}
          A tag-list of other options available under Kickstart version 37
          or greater.  See the `Rom Kernel Reference Manual (Libraries)'
          for more details.

     The screen resolution flags control the screen mode.  The following
     (common) values are taken from the module @{b}graphics/view@{ub} (see @{"Modules" Link "Modules"}).
     You can, if you want, define your own constants for the values that
     you use.  Either way it's best to use descriptive constants rather
     than directly using the values.

          @{i}Mode Flag@{ui}          @{i}Value@{ui}
          ------------------------
          V_LACE                $4
          V_SUPERHIRES         $20
          V_PFBA               $40
          V_EXTRA_HALFBRITE    $80
          V_DUALPF            $400
          V_HAM               $800
          V_HIRES            $8000

     So, to get a hires, interlaced screen you specify both of the flags
     @{b}V_HIRES@{ub} and @{b}V_LACE@{ub}, either by @{b}OR@{ub}-ing the constants or (less readably)
     by using calculated value @{b}$8004@{ub}.  There is a worked example using
     this function in Part Three (see @{"Screens" Link "Screens"}).

@{b}CloseS(@{ub}@{fg shine}scrnptr@{fg text}@{b})@{ub} 
     Closes the screen which is pointed to by @{fg shine}scrnptr@{fg text}.  It's safe to
     give @{b}NIL@{ub} for @{fg shine}scrnptr@{fg text}, but in this case, of course, no screen will
     be closed!  The screen pointer is usually a pointer returned by a
     matching call to @{b}OpenS@{ub}.  You @{i}must@{ui} remember to close any screens you
     may have opened before terminating your program.  Also, you @{i}must@{ui}
     close all windows that you opened on your screen before you can close
     the screen.

@{b}Gadget(@{ub}@{fg shine}buf@{fg text}@{b},@{ub}@{fg shine}glist@{fg text}@{b},@{ub}@{fg shine}id@{fg text}@{b},@{ub}@{fg shine}flags@{fg text}@{b},@{ub}@{fg shine}x@{fg text}@{b},@{ub}@{fg shine}y@{fg text}@{b},@{ub}@{fg shine}width@{fg text}@{b},@{ub}@{fg shine}text@{fg text}@{b})@{ub} 
     Creates a new gadget with the supplied properties and returns a
     pointer to the next position in the (memory) buffer which can be used
     for a gadget.

    @{fg shine}buf@{fg text}
          This is the memory buffer, i.e., a chunk of allocated memory.
          The best way of allocating this memory is to declare an array of
          size @{b}@{ub}@{fg shine}n@{fg text}@{b}*GADGETSIZE@{ub}, where @{fg shine}n@{fg text} is the number of gadgets which
          are going to be created.  The first call to @{b}Gadget@{ub} will use the
          array as the buffer, and subsequent calls use the result of the
          previous call as the buffer (since this function returns the
          next free position in the buffer).

    @{fg shine}glist@{fg text}
          This is a pointer to the gadget list that is being created,
          i.e., the array used as the buffer.  When you create the first
          gadget in the list using an array @{b}a@{ub}, this parameter should be
          @{b}NIL@{ub}.  For all other gadgets in the list this parameter
          should be the array @{b}a@{ub}.

    @{fg shine}id@{fg text}
          A number which identifies the gadget.  It is best to give a
          unique number for each gadget, that way you can easily identify
          them.  This number is the only way you can identify which gadget
          has been clicked.

    @{fg shine}flags@{fg text}
          The type of gadget to be created.  Zero represents a normal
          gadget, one a boolean gadget (a toggle) and three a boolean that
          starts selected.

    @{fg shine}x@{fg text},  @{fg shine}y@{fg text}
          The position of the gadget, relative to the top, left-hand
          corner of the window.

    @{fg shine}width@{fg text}
          The width of the gadget (in pixels, not characters).

    @{fg shine}text@{fg text}
          The text (a string) which will centred in the gadget, so the
          @{fg shine}width@{fg text} must be big enough to hold this text.

     Once a gadget list has been created by possibly several calls to this
     function the list can be passed as the @{fg shine}gads@{fg text} parameter to @{b}OpenW@{ub}.
     There is a worked example using this function in Part Three (see
     @{"Gadgets" Link "Gadgets"}).

@{b}Mouse()@{ub} 
     Returns the state of the mouse buttons (including the middle mouse
     button if you have a three-button mouse).  This is a set of flags,
     and the individual flag values are:

          @{i}Button Pressed@{ui}   @{i}Value@{ui}
          ----------------------
          Left              %001
          Right             %010
          Middle            %100

     So, if this function returns @{b}%001@{ub} you know the left button is being
     pressed, and if it returns @{b}%110@{ub} you know the middle and right buttons
     are both being pressed.

     This mouse function is not strictly the proper way to do things.  It
     is suggested you use this function only for small tests or demo-like
     programs.  The proper way of getting mouse details is to use the
     appropriate IDCMP flags for your window, wait for events and decode
     the information.

@{b}MouseX(@{ub}@{fg shine}winptr@{fg text}@{b})@{ub} 
     Returns the @{fg shine}x@{fg text} coordinate of the mouse pointer, relative to the
     window pointed to by @{fg shine}winptr@{fg text}.

     This mouse function is not strictly the proper way to do things.  It
     is suggested you use this function only for small tests or demo-like
     programs.  The proper way of getting mouse details is to use the
     appropriate IDCMP flags for your window, wait for events and decode
     the information.

@{b}MouseY(@{ub}@{fg shine}winptr@{fg text}@{b})@{ub} 
     Returns the @{fg shine}y@{fg text} coordinate of the mouse pointer, relative to the
     window pointed to by @{fg shine}winptr@{fg text}.

     This mouse function is not strictly the proper way to do things.  It
     is suggested you use this function only for small tests or demo-like
     programs.  The proper way of getting mouse details is to use the
     appropriate IDCMP flags for your window, wait for events and decode
     the information.

@{b}LeftMouse(@{ub}@{fg shine}winptr@{fg text}@{b})@{ub} 
     Returns @{b}TRUE@{ub} if left mouse button has been clicked in the window
     pointed to by @{fg shine}winptr@{fg text}, and @{b}FALSE@{ub} otherwise.  In order for this to
     work sensibly the window must have the IDCMP flag @{b}IDCMP_MOUSEBUTTONS@{ub}
     set (see above).

     This function does things in a proper, Intuition-friendly manner and
     so is a good alternative to the @{b}Mouse@{ub} function.

@{b}WaitIMessage(@{ub}@{fg shine}winptr@{fg text}@{b})@{ub} 
     This function waits for a message from Intuition for the window
     pointed to by @{fg shine}winptr@{fg text} and returns the class of the message (which is
     an IDCMP flag).  If you did not specify any IDCMP flags when the
     window was opened, or the specified messages could never happen
     (e.g., you asked only for gadget messages and you have no gadgets),
     then this function may wait forever.  When you've got a message you
     can use the @{b}MsgXXX@{ub} functions to get some more information about the
     message.  See the `Rom Kernel Reference Manual (Libraries)' for more
     details on Intuition and IDCMP.  There is a worked example using this
     function in Part Three (see @{"IDCMP Messages" Link "IDCMP Messages"}).

     This function is basically equivalent to the following function,
     except that the @{b}MsgXXX@{ub} functions can also access the message data
     held in the variables @{b}code@{ub}, @{b}qual@{ub} and @{b}iaddr@{ub}.

          PROC waitimessage(win:PTR TO window)
            DEF port,msg:PTR TO intuimessage,class,code,qual,iaddr
            port:=win.userport
            IF (msg:=GetMsg(port))=NIL
              REPEAT
                WaitPort(port)
              UNTIL (msg:=GetMsg(port))<>NIL
            ENDIF
            class:=msg.class
            code:=msg.code
            qual:=msg.qualifier
            iaddr:=msg.iaddress
            ReplyMsg(msg)
          ENDPROC class

@{b}MsgCode()@{ub} 
     Returns the @{b}code@{ub} part of the message returned by @{b}WaitIMessage@{ub}.

@{b}MsgIaddr()@{ub} 
     Returns the @{b}iaddr@{ub} part of the message returned by @{b}WaitIMessage@{ub}.
     There is a worked example using this function in Part Three (see
     @{"IDCMP Messages" Link "IDCMP Messages"}).

@{b}MsgQualifier()@{ub} 
     Returns the @{b}qual@{ub} part of the message returned by @{b}WaitIMessage@{ub}.

@{b}WaitLeftMouse(@{ub}@{fg shine}winptr@{fg text}@{b})@{ub} 
     This function waits for the left mouse button to be clicked in the
     window pointed to by @{fg shine}winptr@{fg text}.  It is advisable to have the IDCMP
     flag @{b}IDCMP_MOUSEBUTTONS@{ub} set for the window (see above).

     This function does things in a proper, Intuition-friendly manner and
     so is a good alternative to the @{b}Mouse@{ub} function.


@EndNode

@Node "Graphics functions" "beginner.guide/Graphics functions"
@Next "Maths and logic functions"
@Prev "Intuition support functions"
@Toc "Built-In Functions"

Graphics functions
------------------

   The functions in this section use the standard raster port, the address
of which is held in the variable @{b}stdrast@{ub}.  Most of the time you don't need
to worry about this because the E functions which open windows and screens
set up this variable (see @{"Intuition support functions" Link "Intuition support functions"}).  So, by default,
these functions affect the last window or screen opened.  When you close a
window or screen, @{b}stdrast@{ub} becomes @{b}NIL@{ub} and calls to these functions have no
effect.  There is a worked example using these functions in Part Three
(see @{"Graphics" Link "Graphics"}).

   The descriptions in this section follow the same style as the previous
section.

@{b}Plot(@{ub}@{fg shine}x@{fg text}@{b},@{ub}@{fg shine}y@{fg text}@{b},@{ub}@{fg shine}pen@{fg text}@{b}=1)@{ub} 
     Plots a single point (@{fg shine}x@{fg text},@{fg shine}y@{fg text}) in the specified pen colour.  The
     position is relative to the top, left-hand corner of the window or
     screen that is the current raster port (normally the last screen or
     window to be opened).  The range of pen values available depend on
     the screen setup, but are at best 0-255 on AGA machines and 0-31 on
     pre-AGA machines.  As a guide, the background colour is usually pen
     zero, and the main foreground colour is pen one (and this is the
     default pen).  You can set the colours of pens using the @{b}SetColour@{ub}
     function.

@{b}Line(@{ub}@{fg shine}x1@{fg text}@{b},@{ub}@{fg shine}y1@{fg text}@{b},@{ub}@{fg shine}x2@{fg text}@{b},@{ub}@{fg shine}y2@{fg text}@{b},@{ub}@{fg shine}pen@{fg text}@{b}=1)@{ub} 
     Draws the line (@{fg shine}x1@{fg text},@{fg shine}y1@{fg text}) to (@{fg shine}x2@{fg text},@{fg shine}y2@{fg text}) in the specified pen colour.

@{b}Box(@{ub}@{fg shine}x1@{fg text}@{b},@{ub}@{fg shine}y1@{fg text}@{b},@{ub}@{fg shine}x2@{fg text}@{b},@{ub}@{fg shine}y2@{fg text}@{b},@{ub}@{fg shine}pen@{fg text}@{b}=1)@{ub} 
     Draws the (filled) box with vertices (@{fg shine}x1@{fg text},@{fg shine}y1@{fg text}), (@{fg shine}x2@{fg text},@{fg shine}y1@{fg text}),
     (@{fg shine}x1@{fg text},@{fg shine}y2@{fg text}) and (@{fg shine}x2@{fg text},@{fg shine}y2@{fg text}) in the
     specified pen colour.

@{b}Colour(@{ub}@{fg shine}fore-pen@{fg text}@{b},@{ub}@{fg shine}back-pen@{fg text}@{b}=0)@{ub} 
     Sets the foreground and background pen colours.  As mentioned above,
     the background colour is normally pen zero and the main foreground is
     pen one.  You can change these defaults with this function, and if
     you stick to having the background pen as pen zero then calling this
     function with one argument changes just the foreground pen.

@{b}TextF(@{ub}@{fg shine}x@{fg text}@{b},@{ub}@{fg shine}y@{fg text}@{b},@{ub}@{fg shine}format-string@{fg text}@{b},@{ub}@{fg shine}arg1@{fg text}@{b},@{ub}@{fg shine}arg2@{fg text}@{b},...)@{ub} 
     This works just like @{b}WriteF@{ub} except the resulting string is written
     starting at point (@{fg shine}x@{fg text},@{fg shine}y@{fg text}).  Also, don't use any line-feed, carriage
     return, tab or escape characters in the string--they don't behave
     like they do in @{b}WriteF@{ub}.

@{b}SetColour(@{ub}@{fg shine}scrnptr@{fg text}@{b},@{ub}@{fg shine}pen@{fg text}@{b},@{ub}@{fg shine}r@{fg text}@{b},@{ub}@{fg shine}g@{fg text}@{b},@{ub}@{fg shine}b@{fg text}@{b})@{ub} 
     Sets the colour of colour register @{fg shine}pen@{fg text} for the screen pointed to by
     @{fg shine}scrnptr@{fg text} to be the appropriate RGB value (i.e., red value @{fg shine}r@{fg text}, green
     value @{fg shine}g@{fg text} and blue value @{fg shine}b@{fg text}).  The @{b}pen@{ub} can be anything up to 255,
     depending on the screen depth.  Regardless of the chipset being used,
     @{fg shine}r@{fg text}, @{fg shine}g@{fg text} and @{fg shine}b@{fg text} are taken from the range zero to 255, so 24-bit
     colours are always specified.  In operation, though, the values are
     scaled to 12-bit colour for non-AGA machines.

@{b}SetStdRast(@{ub}@{fg shine}newrast@{fg text}@{b})@{ub} 
     Returns the value of @{b}stdrast@{ub} before setting it to the new value.  The
     following code fragments are equivalent:

            oldstdrast:=SetStdRast(newstdrast)
          
            oldstdrast:=stdrast
            stdrast:=newstdrast

@{b}SetTopaz(@{ub}@{fg shine}size@{fg text}@{b}=8)@{ub} 
     Sets the text font for the current raster port to Topaz at the
     specified size, which defaults to the standard size eight.


@EndNode

@Node "Maths and logic functions" "beginner.guide/Maths and logic functions"
@Next "System support functions"
@Prev "Graphics functions"
@Toc "Built-In Functions"

Maths and logic functions
-------------------------

   We've already seen the standard arithmetic operators.  The addition, @{b}+@{ub},
and subtraction, @{b}-@{ub}, operators use full 32-bit integers, but, for
efficiency, multiplication, @{b}*@{ub}, and division, @{b}/@{ub}, use restricted values.
You can only use @{b}*@{ub} to multiply 16-bit integers, and the result will be a
32-bit integer.  Similarly, you can only use @{b}/@{ub} to divide a 32-bit integer
by a 16-bit integer, and the result will be a 16-bit integer.  The
restrictions do not affect most calculations, but if you really need to
use all 32-bit integers (and you can cope with overflows etc.) you can use
the @{b}Mul@{ub} and @{b}Div@{ub} functions.  @{b}Mul(a,b)@{ub} corresponds to @{b}a*b@{ub}, and @{b}Div(a,b)@{ub}
corresponds to @{b}a/b@{ub}.

   We've also met the logic operators @{b}AND@{ub} and @{b}OR@{ub}, which we know are really
bit-wise operators.  You can also use the functions @{b}And@{ub} and @{b}Or@{ub} to do
exactly the same as @{b}AND@{ub} and @{b}OR@{ub} (respectively).  So, for instance, @{b}And(a,b)@{ub}
is the same as @{b}a AND b@{ub}.  The reason for these functions is because there
are @{b}Not@{ub} and @{b}Eor@{ub} (bit-wise) functions, too (and there aren't operators for
these).  @{b}Not(a)@{ub} swaps one and zero bits, so, for instance, @{b}Not(TRUE)@{ub} is
@{b}FALSE@{ub} and @{b}Not(FALSE)@{ub} is @{b}TRUE@{ub}.  @{b}Eor(a,b)@{ub} is the exclusive version of @{b}Or@{ub} and
does almost the same, except that @{b}Eor(1,1)@{ub} is 0 whereas @{b}Or(1,1)@{ub} is 1 (and
this extends to all the bits).  So, basically, @{b}Eor@{ub} tells you which bits
are different, or, logically, if the truth values are different.
Therefore, @{b}Eor(TRUE,TRUE)@{ub} is @{b}FALSE@{ub} and @{b}Eor(TRUE,FALSE)@{ub} is @{b}TRUE@{ub}.

   There's a collection of other functions related to maths, logic or
numbers in general:

@{b}Abs(@{ub}@{fg shine}expression@{fg text}@{b})@{ub} 
     Returns the absolute value of @{fg shine}expression@{fg text}.  The absolute value of a
     number is that number made positive if necessary.  So, @{b}Abs(9)@{ub} is 9,
     and @{b}Abs(-9)@{ub} is also 9.

@{b}Sign(@{ub}@{fg shine}expression@{fg text}@{b})@{ub} 
     Returns the sign of @{fg shine}expression@{fg text}, which is the value one if it is
     (strictly) positive, -1 if it is (strictly) negative and zero if it
     is zero.

@{b}Even(@{ub}@{fg shine}expression@{fg text}@{b})@{ub} 
     Returns @{b}TRUE@{ub} if @{fg shine}expression@{fg text} represents an even number, and @{b}FALSE@{ub}
     otherwise.  Obviously, a number is either odd or even!

@{b}Odd(@{ub}@{fg shine}expression@{fg text}@{b})@{ub} 
     Returns @{b}TRUE@{ub} if @{fg shine}expression@{fg text} represents an odd number, and @{b}FALSE@{ub}
     otherwise.

@{b}Max(@{ub}@{fg shine}exp1@{fg text}@{b}, @{ub}@{fg shine}exp2@{fg text}@{b})@{ub} 
     Returns the maximum of @{fg shine}exp1@{fg text} and @{fg shine}exp2@{fg text}.

@{b}Min(@{ub}@{fg shine}exp1@{fg text}@{b}, @{ub}@{fg shine}exp2@{fg text}@{b})@{ub} 
     Returns the minimum of @{fg shine}exp1@{fg text} and @{fg shine}exp2@{fg text}.

@{b}Bounds(@{ub}@{fg shine}exp@{fg text}@{b}, @{ub}@{fg shine}minexp@{fg text}@{b}, @{ub}@{fg shine}maxexp@{fg text}@{b})@{ub} 
     Returns the value of @{fg shine}exp@{fg text} bounded to the limits @{fg shine}minexp@{fg text} (minimum
     bound) and @{fg shine}maxexp@{fg text} (maximum bound).  That is, if @{fg shine}exp@{fg text} lies between
     the bounds then @{fg shine}exp@{fg text} is returned, but if it is less than @{fg shine}minexp@{fg text}
     then @{fg shine}minexp@{fg text} is returned or if it is greater than @{fg shine}maxexp@{fg text} then
     @{fg shine}maxexp@{fg text} is returned.  This is useful for, say, constraining a
     calculated value to be a valid (integer) percentage (i.e., a value
     between zero and one hundred).

     The following code fragments are equivalent:

            y:=Bounds(x, min, max)
          
            y:=IF x<min THEN min ELSE IF x>max THEN max ELSE x

@{b}Mod(@{ub}@{fg shine}exp1@{fg text}@{b},@{ub}@{fg shine}exp2@{fg text}@{b})@{ub} 
     Returns the 16-bit remainder (or modulus) of the division of the
     32-bit @{fg shine}exp1@{fg text} by the 16-bit @{fg shine}exp2@{fg text} as the regular return value (see
     @{"Multiple Return Values" Link "Multiple Return Values"}), and the 16-bit result of the division as the
     first optional return value.  For example, the first assignment in
     the following code sets @{b}a@{ub} to 5 (since 26=(7*3)+5), @{b}b@{ub} to 3, @{b}c@{ub} to -5
     and @{b}d@{ub} to -3.  It is important to notice that if @{fg shine}exp1@{fg text} is negative
     then the modulus will also be negative.  This is because of the way
     integer division works: it simply discards fractional parts rather
     rounding.

            a,b:=Mod(26,7)
            c,d:=Mod(-26,7)

@{b}Rnd(@{ub}@{fg shine}expression@{fg text}@{b})@{ub} 
     Returns a random number in the range 0 to (n-1), where @{fg shine}expression@{fg text}
     represents the value n.  These numbers are pseudo-random, so although
     you appear to get a random value from each call, the sequence of
     numbers you get will probably be the same each time you run your
     program.  Before you use @{b}Rnd@{ub} for the first time in your program you
     should call it with a negative number.  This decides the starting
     point for the pseudo-random numbers.

@{b}RndQ(@{ub}@{fg shine}expression@{fg text}@{b})@{ub} 
     Returns a random 32-bit value, based on the seed @{fg shine}expression@{fg text}.  This
     function is quicker than @{b}Rnd@{ub}, but returns values in the 32-bit range,
     not a specified range.  The seed value is used to select different
     sequences of pseudo-random numbers, and the first call to @{b}RndQ@{ub} should
     use a large value for the seed.

@{b}Shl(@{ub}@{fg shine}exp1@{fg text}@{b},@{ub}@{fg shine}exp2@{fg text}@{b})@{ub} 
     Returns the value represented by @{fg shine}exp1@{fg text} shifted @{fg shine}exp2@{fg text} bits to the
     left.  For example, @{b}Shl(%0001110,2)@{ub} is @{b}%0111000@{ub} and @{b}Shl(%0001011,3)@{ub}
     is @{b}%1011000@{ub}.  Shifting a number one bit to the left is generally the
     same as multiplying it by two (although this isn't true when you
     shift large positive or large negative values).  (The new bits
     shifted in at the right are always zeroes.)

@{b}Shr(@{ub}@{fg shine}exp1@{fg text}@{b},@{ub}@{fg shine}exp2@{fg text}@{b})@{ub} 
     Returns the value represented by @{fg shine}exp1@{fg text} shifted @{fg shine}exp2@{fg text} bits to the
     right.  For example, @{b}Shr(%0001110,2)@{ub} is @{b}%0000011@{ub} and @{b}Shr(%1011010,3)@{ub}
     is @{b}%0001011@{ub}.  Shifting a number one bit to the right is generally the
     same as dividing it by two.  (The new bits shifted in at the left are
     always zeroes.)

@{b}Long(@{ub}@{fg shine}addr@{fg text}@{b}),  Int(@{ub}@{fg shine}addr@{fg text}@{b}),  Char(@{ub}@{fg shine}addr@{fg text}@{b})@{ub} 
     Returns the @{b}LONG@{ub}, @{b}INT@{ub} or @{b}CHAR@{ub} value at the address @{fg shine}addr@{fg text}.  These
     functions should be used only when setting up a pointer and
     dereferencing it in the normal way would make your program cluttered
     and less readable.  Use of functions like these is often called
     @{fg shine}peeking@{fg text} memory (especially in dialects of the BASIC language).

@{b}PutLong(@{ub}@{fg shine}addr@{fg text}@{b},@{ub}@{fg shine}exp@{fg text}@{b}),  PutInt(@{ub}@{fg shine}addr@{fg text}@{b},@{ub}@{fg shine}exp@{fg text}@{b}),  PutChar(@{ub}@{fg shine}addr@{fg text}@{b},@{ub}@{fg shine}exp@{fg text}@{b})@{ub} 
     Writes the @{b}LONG@{ub}, @{b}INT@{ub} or @{b}CHAR@{ub} value represented by @{fg shine}exp@{fg text} to the
     address @{fg shine}addr@{fg text}.  Again, these functions should be used only when
     really necessary.  Use of functions like these is often called
     @{fg shine}poking@{fg text} memory.


@EndNode

@Node "System support functions" "beginner.guide/System support functions"
@Prev "Maths and logic functions"
@Toc "Built-In Functions"

System support functions
------------------------

@{b}New(@{ub}@{fg shine}bytes@{fg text}@{b})@{ub} 
     Returns a pointer to a newly allocated chunk of memory, which is
     @{fg shine}bytes@{fg text} number of bytes.  If the memory could not be allocated @{b}NIL@{ub} is
     returned.  The memory is initialised to zero in each byte, and taken
     from any available store (Fast or Chip memory, in that order of
     preference).  When you've finished with this memory you can use
     @{b}Dispose@{ub} to free it for use elsewhere in your program.  You don't have
     to @{b}Dispose@{ub} with memory you allocated with @{b}New@{ub} because your program
     will automatically free it when it terminates.  This is @{i}not@{ui} true for
     memory allocated using the normal Amiga system routines.

@{b}NewR(@{ub}@{fg shine}bytes@{fg text}@{b})@{ub} 
     The same as @{b}New@{ub} except that if the memory could not be allocated then
     the exception @{b}"MEM"@{ub} is raised (and so, in this case, the function
     does not return).  See @{"Exception Handling" Link "Exception Handling"}.

@{b}NewM(@{ub}@{fg shine}bytes@{fg text}@{b},@{ub}@{fg shine}type@{fg text}@{b})@{ub} 
     The same as @{b}NewR@{ub} except that the @{fg shine}type@{fg text} of memory (Fast or Chip) to
     be allocated can be specified using flags.  The flags are defined in
     the module @{b}exec/memory@{ub} (see @{"Amiga System Modules" Link "Amiga System Modules"}).  See the `Rom
     Kernel Reference Manual (Libraries)' for details about the system
     function @{b}AllocMem@{ub} which uses these flags in the same way.  As useful
     example, here's a small program which allocates some cleared (i.e.,
     zeroed) Chip memory.

          MODULE 'exec/memory'
          
          PROC main()
            DEF m
            m:=NewM(20, MEMF_CHIP OR MEMF_CLEAR)
            WriteF('Allocation succeeded, m = $\h\n', m)
          EXCEPT
            IF exception="NEW" THEN WriteF('Failed\n')
          ENDPROC

@{b}Dispose(@{ub}@{fg shine}address@{fg text}@{b})@{ub} 
     Used to free memory allocated with @{b}New@{ub}, @{b}NewR@{ub} or @{b}NewM@{ub}.  You should
     rarely need to use this function because the memory is automatically
     freed when the program terminates.

@{b}DisposeLink(@{ub}@{fg shine}complex@{fg text}@{b})@{ub} 
     Used to free the memory allocated @{b}String@{ub} (see @{"String functions" Link "String functions"}) and
     @{b}List@{ub} (see @{"List functions" Link "List functions"}).  Again, you should rarely need to use this
     function because the memory is automatically freed when the program
     terminates.

@{b}FastNew(@{ub}@{fg shine}bytes@{fg text}@{b})@{ub} 
     The same as @{b}NewR@{ub} except it uses a very fast, recycling method of
     allocating memory.  The memory allocated using @{b}FastNew@{ub} is, as ever,
     deallocated automatically at the end of a program, and can be
     deallocated before then using @{b}FastDispose@{ub}.  Note that only
     @{b}FastDispose@{ub} can be used and that it differs slightly from the
     @{b}Dispose@{ub} and @{b}DisposeLink@{ub} functions (you have to specify the number of
     bytes originally allocated when deallocating).

@{b}FastDispose(@{ub}@{fg shine}address@{fg text}@{b},@{ub}@{fg shine}bytes@{fg text}@{b})@{ub} 
     Used to free the memory allocated using @{b}FastNew@{ub}.  The @{fg shine}bytes@{fg text}
     parameter must be the same as the @{fg shine}bytes@{fg text} used when allocating with
     @{b}FastNew@{ub}, but the benefit is much faster allocation and deallocation
     and generally more efficient use of memory.

@{b}CleanUp(@{ub}@{fg shine}expression@{fg text}@{b}=0)@{ub} 
     Terminates the program at this point, and does the normal things an E
     program does when it finishes.  The value denoted by @{fg shine}expression@{fg text} is
     returned as the error code for the program.  It is the replacement
     for the AmigaDOS @{b}Exit@{ub} routine which should @{i}never@{ui} be used in an E
     program.  This is the only safe way of terminating a program, other
     than reaching the (logical) end of the @{b}main@{ub} procedure (which is by
     far the most common way!).

@{b}CtrlC()@{ub} 
     Returns @{b}TRUE@{ub} if control-C has been pressed since the last call, and
     @{b}FALSE@{ub} otherwise.  This is only sensible for programs started from the
     Shell/CLI.

@{b}FreeStack()@{ub} 
     Returns the current amount of free stack space for the program.  Only
     complicated programs need worry about things like stack.  Recursion
     is the main thing that eats a lot of stack space.

@{b}KickVersion(@{ub}@{fg shine}expression@{fg text}@{b})@{ub} 
     Returns @{b}TRUE@{ub} if your Kickstart revision is at least that given by
     @{fg shine}expression@{fg text}, and @{b}FALSE@{ub} otherwise.  For instance, @{b}KickVersion(37)@{ub}
     checks whether you're running with Kickstart version 37 or greater
     (i.e., AmigaDOS 2.04 and above).


@EndNode

@Node "Modules" "beginner.guide/Modules"
@Next "Exception Handling"
@Prev "E Built-In Constants Variables and Functions"
@Toc "Main"

Modules
*******

   A @{fg shine}module@{fg text} is the E equivalent of a C header file and an Assembly
include file.  It can contain various object and constant definitions, and
also library function offsets and library base variables.  This information is
necessary for the correct use of a library.


 @{" Using Modules " Link "Using Modules"} 
 @{" Amiga System Modules " Link "Amiga System Modules"} 
 @{" Non-Standard Modules " Link "Non-Standard Modules"} 
 @{" Example Module Use " Link "Example Module Use"} 
 @{" Code Modules " Link "Code Modules"} 


@EndNode

@Node "Using Modules" "beginner.guide/Using Modules"
@Next "Amiga System Modules"
@Toc "Modules"

Using Modules
=============

   To use the definitions in a particular module you use the @{b}MODULE@{ub}
statement at the beginning of your program (before the first procedure
definition).  You follow the @{b}MODULE@{ub} keyword by a comma-separated list of
strings, each of which is the filename (or path if necessary) of a module
without the @{b}.m@{ub} extension (every module file ends with @{b}.m@{ub}).  The filenames
(and paths) are all relative to the logical volume @{b}Emodules:@{ub}, which is
set-up using an @{b}assign@{ub} as described in the `Reference Manual', unless the
first character of the string is @{b}*@{ub}.  In this case the files are relative
to the directory of the current source file.  For instance, the statement:

     MODULE 'fred', 'dir/barney', '*mymod'

will try to load the files @{b}Emodules:fred.m@{ub}, @{b}Emodules:dir/barney.m@{ub} and
@{b}mymod.m@{ub}.  If it can't find these files or they aren't proper modules the E
compiler will complain.

   All the definitions in the modules included in this way are available
to every procedure in the program.  To see what a module contains you can
use the @{b}showmodule@{ub} program that comes with the Amiga E distribution.


@EndNode

@Node "Amiga System Modules" "beginner.guide/Amiga System Modules"
@Next "Non-Standard Modules"
@Prev "Using Modules"
@Toc "Modules"

Amiga System Modules
====================

   Amiga E comes with the standard Amiga system include files as E modules.
The AmigaDOS 2.04 modules are supplied with E version 2.1, and the
AmigaDOS 3.0 modules are supplied with E version 3.0.  However, modules
are much more useful in E version 3.0 (see @{"Code Modules" Link "Code Modules"}).  If you want to
use any of the standard Amiga libraries properly you will need to
investigate the modules for that library.  The top-level @{b}.m@{ub} files in
@{b}Emodules:@{ub} contain the library function offsets, and those in directories
in @{b}Emodules:@{ub} contain constant and object definitions for the appropriate
library.  For instance, the module @{b}asl@{ub} (i.e., the file @{b}Emodules:asl.m@{ub})
contains the ASL library function offsets and @{b}libraries/asl@{ub} contains the
ASL library constants and objects.

   If you are going to use, say, the ASL library then you need to open the
library using the @{b}OpenLibrary@{ub} function (an Amiga system function) before
you can use any of the library functions.  You also need to define the
library function offsets by using the @{b}MODULE@{ub} statement.  However, the DOS,
Exec, Graphics and Intuition libraries don't need to be opened and their
function offsets are built in to E. That's why you won't find, for
example, a @{b}dos.m@{ub} file in @{b}Emodules:@{ub}.  The constants and objects for these
libraries still need to be included via modules (they are not built in to
E).


@EndNode

@Node "Non-Standard Modules" "beginner.guide/Non-Standard Modules"
@Next "Example Module Use"
@Prev "Amiga System Modules"
@Toc "Modules"

Non-Standard Modules
====================

   Several non-standard library modules are also supplied with Amiga E. To
make your own modules you need the @{b}pragma2module@{ub} and @{b}iconvert@{ub} programs.
These convert standard format C header files and Assembly include files to
modules.  The C header file should contain pragmas for function offsets,
and the Assembly include file should contain constant and structure
definitions (the Assembly structures will be converted to objects).
However, unless you're trying to do really advanced things you probably
don't need to worry about any of this!


@EndNode

@Node "Example Module Use" "beginner.guide/Example Module Use"
@Next "Code Modules"
@Prev "Non-Standard Modules"
@Toc "Modules"

Example Module Use
==================

   The gadget example program in Part Three shows how to use constants
from the module @{b}intuition/intuition@{ub} (see @{"Gadgets" Link "Gadgets"}), and the IDCMP example
program shows the object @{b}gadget@{ub} from that module being used (see
@{"IDCMP Messages" Link "IDCMP Messages"}).  The following program uses the modules for the Reqtools
library, which is not a standard Amiga system library but a commonly used
one, and the appropriate modules are supplied with Amiga E. To run this
program, you will, of course, need the @{b}reqtools.library@{ub} in @{b}Libs:@{ub}.

     MODULE 'reqtools'
     
     PROC main()
       DEF col
       IF (reqtoolsbase:=OpenLibrary('reqtools.library',37))<>NIL
         IF (col:=RtPaletteRequestA('Select a colour', 0,0))<>-1
           RtEZRequestA('You picked colour \d',
                        'I did|I can\at remember',0,[col],0)
         ENDIF
         CloseLibrary(reqtoolsbase)
       ELSE
         WriteF('Could not open reqtools.library, version 37+\n')
       ENDIF
     ENDPROC

The @{b}reqtoolsbase@{ub} variable is the library base variable for the Reqtools
library.  This is defined in the module @{b}reqtools@{ub} and you @{i}must@{ui} store the
result of the @{b}OpenLibrary@{ub} call in this variable if you are going to use
any of the functions from the Reqtools library.  (You can find out which
variable to use for other libraries by running the @{b}showmodule@{ub} program on
the library module for the library.) The two functions the program uses
are @{b}RtPaletteRequestA@{ub} and @{b}RtEZRequestA@{ub}.  Without the inclusion of the
@{b}reqtools@{ub} module and the setting up of the @{b}reqtoolsbase@{ub} variable you would
not be able to use these functions.  In fact, if you didn't have the
@{b}MODULE@{ub} line you wouldn't even be able to compile the program because
the compiler wouldn't know where the functions came from and would
complain bitterly.

   Notice that the Reqtools library is closed before the program
terminates (if it had been successfully opened).  This is always
necessary: if you succeed in opening a library you @{i}must@{ui} close it when
you're finished with it.


@EndNode

@Node "Code Modules" "beginner.guide/Code Modules"
@Prev "Example Module Use"
@Toc "Modules"

Code Modules
============

   You can also make modules containing procedure definitions and some
global variables.  These are called @{fg shine}code modules@{fg text} and can be extremely
useful.  This section briefly outlines their construction and use.  For
in-depth details see the `Reference Manual'.

   Code modules can be made by using the E compiler as you would to make
an executable, except you put the statement @{b}OPT MODULE@{ub} at the start of the
code.  Also, all definitions that are to be accessed from outside the
module need to be marked with the @{b}EXPORT@{ub} keyword.  Alternatively, all
definitions can be exported using @{b}OPT EXPORT@{ub} at the start of the code.
You include the definitions from this module (and use the exported ones)
in your program using @{b}MODULE@{ub} in the normal way.

   The following code is an example of a small module:

     OPT MODULE
     
     EXPORT CONST MAX_LEN=20
     
     EXPORT OBJECT fullname
       firstname, surname
     ENDOBJECT
     
     EXPORT PROC printname(p:PTR TO fullname)
       IF short(p.surname)
         WriteF('Hello, \s \s\n', p.firstname, p.surname)
       ELSE
         WriteF('Gosh, you have a long name\n')
       ENDIF
     ENDPROC
     
     PROC short(s)
       RETURN StrLen(s)<MAX_LEN
     ENDPROC

Everything is exported except the @{b}short@{ub} procedure.  Therefore, this can be
accessed only in the module.  In fact, the @{b}printname@{ub} procedure uses it
(rather artificially) to check the length of the @{b}surname@{ub}.  It's not of
much use or interest apart from in the module, so that's why it isn't
exported.  In effect, we've hidden the fact that @{b}printname@{ub} uses @{b}short@{ub} from
the user of the module.

   Assuming the above code was compiled to module @{b}mymods/name@{ub}, here's how
it could be used:

     MODULE 'mymods/name'
     
     PROC main()
       DEF fred:PTR TO fullname, bigname
       fred.firstname:='Fred'
       fred.surname:='Flintstone'
       printname(fred)
       bigname:=['Peter', 'Extremelybiglongprehistoricname']
       printname(bigname)
     ENDPROC

   Global variables in a module are a bit more problematic than the other
kinds of definitions.  You cannot initialise them in the declaration or
make them reserve chunks memory.  So you can't have @{b}ARRAY@{ub}, @{b}OBJECT@{ub}, @{b}STRING@{ub}
or @{b}LIST@{ub} declarations.  However, you can have pointers so this isn't a big
problem.  The reason for this limitation is that exported global variables
with the same name in a module and the main program are taken to be the
same variable, and the values are shared.  So you can have an array
declaration in the main program:

     DEF a[80]:ARRAY OF INT

and the appropriate pointer declaration in the module:

     EXPORT DEF a:PTR TO INT

The array from the main program can then be accessed in the module!  For
this reason you also need to be pretty careful about the names of your
exported variables so you don't get unwanted sharing.  Global variables
which are not exported are private to the module, so will not clash with
variables in the main program or other modules.


@EndNode

@Node "Exception Handling" "beginner.guide/Exception Handling"
@Next "Memory Allocation"
@Prev "Modules"
@Toc "Main"

Exception Handling
******************

   Often your program has to check the results of functions and do
different things if errors have occurred.  For instance, if you try to
open a window (using @{b}OpenW@{ub}), you may get a @{b}NIL@{ub} pointer returned which
shows that the window could not be opened for some reason.  In this case
you normally can't continue with the program, so you must tidy up and
terminate.  Tidying up can sometimes involve closing windows, screens and
libraries, so sometimes your error cases can make your program cluttered
and messy.  This is where exceptions come in--an @{fg shine}exception@{fg text} is simply an
error case, and exception handling is dealing with error cases.  The
exception handling in E neatly separates error specific code from the real
code of your program.


 @{" Procedures with Exception Handlers " Link "Procedures with Exception Handlers"} 
 @{" Raising an Exception " Link "Raising an Exception"} 
 @{" Automatic Exceptions " Link "Automatic Exceptions"} 
 @{" Raise within an Exception Handler " Link "Raise within an Exception Handler"} 


@EndNode

@Node "Procedures with Exception Handlers" "beginner.guide/Procedures with Exception Handlers"
@Next "Raising an Exception"
@Toc "Exception Handling"

Procedures with Exception Handlers
==================================

   A procedure with an exception handler looks like this:

     PROC fred(params...) HANDLE
       /* Main, real code */
     EXCEPT
       /* Error handling code */
     ENDPROC

This is very similar to a normal procedure, apart from the @{b}HANDLE@{ub} and
@{b}EXCEPT@{ub} keywords.  The @{b}HANDLE@{ub} keyword means the procedure is going to have
an exception handler, and the @{b}EXCEPT@{ub} keyword marks the end of the normal
code and the start of the exception handling code.  The procedure works
just as normal, executing the code in the part before the @{b}EXCEPT@{ub}, but when
an error happens you can pass control to the exception handler (i.e., the
code after the @{b}EXCEPT@{ub} is executed).


@EndNode

@Node "Raising an Exception" "beginner.guide/Raising an Exception"
@Next "Automatic Exceptions"
@Prev "Procedures with Exception Handlers"
@Toc "Exception Handling"

Raising an Exception
====================

   When an error occurs (and you want to handle it), you @{fg shine}raise@{fg text} an
exception using either the @{b}Raise@{ub} or @{b}Throw@{ub} function.  You call @{b}Raise@{ub} with a
number which identifies the kind of error that occurred.  The code in the
exception handler is responsible for decoding the number and then doing
the appropriate thing.  @{b}Throw@{ub} is very similar to @{b}Raise@{ub}, and the following
description of @{b}Raise@{ub} also applies to @{b}Throw@{ub}.  The difference is that @{b}Throw@{ub}
takes a second argument which can be used to pass extra information to a
handler (usually a string).  The terms `raising' and `throwing' an
exception can be used interchangeably.

   When @{b}Raise@{ub} is called it immediately stops the execution of the current
procedure code and passes control to the exception handler of most recent
procedure which has a handler (which may be the current procedure).  This
is a bit complicated, but you can stick to raising exceptions and handling
them in the same procedure, as in the next example:

     CONST BIG_AMOUNT = 100000
     
     ENUM ERR_MEM=1
     
     PROC main() HANDLE
       DEF block
       block:=New(BIG_AMOUNT)
       IF block=NIL THEN Raise(ERR_MEM)
       WriteF('Got enough memory\n')
     EXCEPT
       IF exception=ERR_MEM
         WriteF('Not enough memory\n')
       ELSE
         WriteF('Unknown exception\n')
       ENDIF
     ENDPROC

This uses an exception handler to print a message saying there wasn't
enough memory if the call to @{b}New@{ub} returns @{b}NIL@{ub}.  The parameter to @{b}Raise@{ub} is
stored in the special variable @{b}exception@{ub} in the exception handler part of
the code, so if @{b}Raise@{ub} is called with a number other than @{b}ERR_MEM@{ub} a message
saying "Unknown exception" will be printed.

   Try running this program with a really large @{b}BIG_AMOUNT@{ub} constant, so
that the @{b}New@{ub} can't allocate the memory.  Notice that the "Got enough
memory" is not printed if @{b}Raise@{ub} is called.  That's because the execution
of the normal procedure code stops when @{b}Raise@{ub} is called, and control
passes to the appropriate exception handler.  When the end of the
exception handler is reached the procedure is finished, and in this case
the program terminates because the procedure was the @{b}main@{ub} procedure.

   If @{b}Throw@{ub} is used instead of @{b}Raise@{ub} then, in the handler, the special
variable @{b}exceptioninfo@{ub} will contain the value of the second parameter.
This can be used in conjunction with @{b}exception@{ub} to provide the handler with
more information about the error.  Here's the above example re-written to
use @{b}Throw@{ub}:

     CONST BIG_AMOUNT = 100000
     
     ENUM ERR_MEM=1
     
     PROC main() HANDLE
       DEF block
       block:=New(BIG_AMOUNT)
       IF block=NIL THEN Throw(ERR_MEM, 'Not enough memory\n')
       WriteF('Got enough memory\n')
     EXCEPT
       IF exception=ERR_MEM
         WriteF(exceptioninfo)
       ELSE
         WriteF('Unknown exception\n')
       ENDIF
     ENDPROC

   An enumeration (using @{b}ENUM@{ub}) is a good way of getting different
constants for various exceptions.  It's always a good idea to use
constants for the parameter to @{b}Raise@{ub} and in the exception handler, because
it makes everything a lot more readable: @{b}Raise(ERR_MEM)@{ub} is much clearer
than @{b}Raise(1)@{ub}.  The enumeration starts at one because zero is a special
exception: it usually means that no error occurred.  This is useful when
the handler does the same cleaning up that would normally be done when the
program terminates successfully.  For this reason there is a special form
of @{b}EXCEPT@{ub} which automatically raises a zero exception when the code in the
procedure successfully terminates.  This is @{b}EXCEPT DO@{ub}, with the @{b}DO@{ub}
suggesting to the reader that the exception handler is called even if no
error occurs.  Also, the argument to the @{b}Raise@{ub} function defaults to zero
(see @{"Default Arguments" Link "Default Arguments"}) if it is omitted.

   So, what happens if you call @{b}Raise@{ub} in a procedure without an exception
handler?  Well, this is where the real power of the handling mechanism
comes to light.  In this case, control passes to the exception handler of
the most @{fg shine}recent@{fg text} procedure with a handler.  If none are found then the
program terminates.  @{fg shine}Recent@{fg text} means one of the procedures involved in
calling your procedure.  So, if the procedure @{b}fred@{ub} calls @{b}barney@{ub}, then when
@{b}barney@{ub} is being executed @{b}fred@{ub} is a recent procedure.  Because the @{b}main@{ub}
procedure is where the program starts it is a recent procedure for every
other procedure in the program.  This means, in practice:

   @{b}*@{ub} If you define @{b}fred@{ub} to be a procedure with an exception handler then
     any procedures called by @{b}fred@{ub} will have their exceptions handled by
     the handler in @{b}fred@{ub} if they don't have their own handler.

   @{b}*@{ub} If you define @{b}main@{ub} to be a procedure with an exception handler then
     any exceptions that are raised will always be dealt with by some
     exception handling code (i.e., the handler of @{b}main@{ub} or some other
     procedure).

   Here's a more complicated example:

     ENUM FRED=1, BARNEY
     
     PROC main()
       WriteF('Hello from main\n')
       fred()
       barney()
       WriteF('Goodbye from main\n')
     ENDPROC
     
     PROC fred() HANDLE
       WriteF(' Hello from fred\n')
       Raise(FRED)
       WriteF(' Goodbye from fred\n')
     EXCEPT
       WriteF(' Handler fred: \d\n', exception)
     ENDPROC
     
     PROC barney()
       WriteF('  Hello from barney\n')
       Raise(BARNEY)
       WriteF('  Goodbye from barney\n')
     ENDPROC

When you run this program you get the following output:

     Hello from main
      Hello from fred
      Handler fred: 1
       Hello from barney

This is because the @{b}fred@{ub} procedure is terminated by the @{b}Raise(FRED)@{ub} call,
and the whole program is terminated by the @{b}Raise(BARNEY)@{ub} call (since
@{b}barney@{ub} and @{b}main@{ub} do not have handlers).

   Now try this:

     ENUM FRED=1, BARNEY
     
     PROC main()
       WriteF('Hello from main\n')
       fred()
       WriteF('Goodbye from main\n')
     ENDPROC
     
     PROC fred() HANDLE
       WriteF(' Hello from fred\n')
       barney()
       Raise(FRED)
       WriteF(' Goodbye from fred\n')
     EXCEPT
       WriteF(' Handler fred: \d\n', exception)
     ENDPROC
     
     PROC barney()
       WriteF('  Hello from barney\n')
       Raise(BARNEY)
       WriteF('  Goodbye from barney\n')
     ENDPROC

When you run this you get the following output:

     Hello from main
      Hello from fred
       Hello from barney
      Handler fred: 2
     Goodbye from main

Now the @{b}fred@{ub} procedure calls @{b}barney@{ub}, so @{b}main@{ub} and @{b}fred@{ub} are recent
procedures when @{b}Raise(BARNEY)@{ub} is executed, and therefore the @{b}fred@{ub}
exception handler is called.  When this handler finishes the call to @{b}fred@{ub}
in @{b}main@{ub} is finished, so the @{b}main@{ub} procedure is completed and we see the
`Goodbye' message.  In the previous program the @{b}Raise(BARNEY)@{ub} call did not
get handled and the whole program terminated at that point.


@EndNode

@Node "Automatic Exceptions" "beginner.guide/Automatic Exceptions"
@Next "Raise within an Exception Handler"
@Prev "Raising an Exception"
@Toc "Exception Handling"

Automatic Exceptions
====================

   In the previous section we saw an example of raising an exception when
a call to @{b}New@{ub} returned @{b}NIL@{ub}.  We can re-write this example to use
@{fg shine}automatic@{fg text} exception raising:

     CONST BIG_AMOUNT = 100000
     
     ENUM ERR_MEM=1
     
     RAISE ERR_MEM IF New()=NIL
     
     PROC main() HANDLE
       DEF block
       block:=New(BIG_AMOUNT)
       WriteF('Got enough memory\n')
     EXCEPT
       IF exception=ERR_MEM
         WriteF('Not enough memory\n')
       ELSE
         WriteF('Unknown exception\n')
       ENDIF
     ENDPROC

The only difference is the removal of the @{b}IF@{ub} which checked the value of
@{b}block@{ub}, and the addition of a @{b}RAISE@{ub} part.  This @{b}RAISE@{ub} part means that
whenever the @{b}New@{ub} function is called in the program, the exception @{b}ERR_MEM@{ub}
will be raised if it returns @{b}NIL@{ub} (i.e., the exception @{b}ERR_MEM@{ub} is
automatically raised).  This unclutters the program by removing a lot of
error checking @{b}IF@{ub} statements.

   The precise form of the @{b}RAISE@{ub} part is:

     RAISE @{fg shine}exception@{fg text}  IF @{fg shine}function@{fg text}()  @{fg shine}compare@{fg text}  @{fg shine}value@{fg text} ,
           @{fg shine}exception2@{fg text} IF @{fg shine}function2@{fg text}() @{fg shine}compare2@{fg text} @{fg shine}value2@{fg text} ,
           ...

The @{fg shine}exception@{fg text} is a constant (or number) which represents the exception
to be raised, @{fg shine}function@{fg text} is the E built-in or system function to be
automatically checked, @{fg shine}value@{fg text} is the return value to be checked against,
and  @{fg shine}compare@{fg text} is the method of checking (i.e., @{b}=@{ub}, @{b}<>@{ub}, @{b}<@{ub}, @{b}<=@{ub}, @{b}>@{ub} or @{b}>=@{ub}).
This mechanism only exists for built-in or library functions because they
would otherwise have no way of raising exceptions.  The procedures you
define yourself can, of course, use @{b}Raise@{ub} to raise exceptions in a much
more flexible way.


@EndNode

@Node "Raise within an Exception Handler" "beginner.guide/Raise within an Exception Handler"
@Prev "Automatic Exceptions"
@Toc "Exception Handling"

@{b}Raise@{ub} within an Exception Handler
=================================

   If you call @{b}Raise@{ub} within an exception handler then control passes to
the next most recent handler.  In this way you can write procedures which
have handlers that perform local tidying up.  By using @{b}Raise@{ub} at the end of
the handler code you can invoke the next layer of tidying up.

   As an example we'll use the Amiga system functions @{b}AllocMem@{ub} and @{b}FreeMem@{ub}
which are like the built-in function @{b}New@{ub} and @{b}Dispose@{ub}, but the memory
allocated by @{b}AllocMem@{ub} @{i}must@{ui} be deallocated (using @{b}FreeMem@{ub}) when it's
finished with, before the end of the program.

     CONST SMALL=100, BIG=123456789
     
     ENUM ERR_MEM=1
     
     RAISE ERR_MEM IF AllocMem()=NIL
     
     PROC main()
       allocate()
     ENDPROC
     
     PROC allocate() HANDLE
       DEF mem=NIL
       mem:=AllocMem(SMALL, 0)
       morealloc()
       FreeMem(mem, SMALL)
     EXCEPT
       IF mem THEN FreeMem(mem, SMALL)
       WriteF('Handler: deallocating "allocate" local memory\n')
     ENDPROC
     
     PROC morealloc() HANDLE
       DEF more=NIL, andmore=NIL
       more:=AllocMem(SMALL, 0)
       andmore:=AllocMem(BIG, 0)
       WriteF('Allocated all the memory!\n')
       FreeMem(andmore, BIG)
       FreeMem(more, SMALL)
     EXCEPT
       IF andmore THEN FreeMem(andmore, BIG)
       IF more THEN FreeMem(more, SMALL)
       WriteF('Handler: deallocating "morealloc" local memory\n')
       Raise(ERR_MEM)
     ENDPROC

The calls to @{b}AllocMem@{ub} are automatically checked, and if @{b}NIL@{ub} is returned
the exception @{b}ERR_MEM@{ub} is raised.  The handler in the @{b}allocate@{ub} procedure
checks to see if it needs to free the memory pointed to by @{b}mem@{ub}, and the
handler in the @{b}morealloc@{ub} checks @{b}andmore@{ub} and @{b}more@{ub}.  At the end of the
@{b}morealloc@{ub} handler is the call @{b}Raise(ERR_MEM)@{ub}.  This passes control to the
exception handler of the @{b}allocate@{ub} procedure, since @{b}allocate@{ub} called
@{b}morealloc@{ub}.

   There's a couple of subtle points to notice about this example.
Firstly, the memory variables are all initialised to @{b}NIL@{ub}.  This is because
the automatic exception raising on @{b}AllocMem@{ub} will result in the variables
not being assigned if the call returns @{b}NIL@{ub} (i.e., the exception is raised
before the assignment takes place), and the handler needs them to be @{b}NIL@{ub}
if @{b}AllocMem@{ub} fails.  Of course, if @{b}AllocMem@{ub} does not return @{b}NIL@{ub} the
assignments work as normal.

   Secondly, the @{b}IF@{ub} statements in the handlers check the memory pointer
variables do not contain @{b}NIL@{ub} by using their values as truth values.  Since
@{b}NIL@{ub} is actually zero, a non-@{b}NIL@{ub} pointer will be non-zero, i.e., true in
the @{b}IF@{ub} check.  This shorthand is often used, and so you should be aware of
it.

   It is quite common that an exception handler will want to raise the
same exception after it has done its processing.  The function @{b}ReThrow@{ub}
(which has no arguments) can be used for this purpose.  It will re-raise
the exception, but only if the exception is not zero (since this special
value means that no error occurred).  If the exception is zero then this
function has no effect.  In fact, the following code fragments (within a
handler) are equivalent:

       ReThrow()
     
       IF exception THEN Throw(exception, exceptioninfo)

   There are two examples, in Part Three, of how to use an exception
handler to make a program more readable: one deals with using data files
(see @{"String Handling and I-O" Link "String Handling and I-O"}) and the other deals with opening screens and
windows (see @{"Screens" Link "Screens"}).


@EndNode

@Node "Memory Allocation" "beginner.guide/Memory Allocation"
@Next "Floating-Point Numbers"
@Prev "Exception Handling"
@Toc "Main"

Memory Allocation
*****************

   When a program is running memory is being used in various different
ways.  In order to use any memory it must first be @{fg shine}allocated@{fg text}, which is
simply a way of marking memory as being `in use'.  This is to prevent the
same piece of memory being used for different data storage (e.g., by
different programs), and so helps prevent corruption of the data stored
there.  There are two general ways in which memory can be allocated:
dynamically and statically.


 @{" Static Allocation " Link "Static Allocation"} 
 @{" Deallocation of Memory " Link "Deallocation of Memory"} 
 @{" Dynamic Allocation " Link "Dynamic Allocation"} 
 @{" NEW and END Operators " Link "NEW and END Operators"} 


@EndNode

@Node "Static Allocation" "beginner.guide/Static Allocation"
@Next "Deallocation of Memory"
@Toc "Memory Allocation"

Static Allocation
=================

   @{fg shine}Statically@{fg text} allocated memory is memory allocated by the program for
variables and static data like string constants, lists and typed lists
(see @{"Static data" Link "Static data"}).  Every variable in a program requires some memory in
which to store its value.  Variables declared to be of type @{b}ARRAY@{ub}, @{b}LIST@{ub},
@{b}STRING@{ub} or any object require two lots of memory: one to hold the value of
the pointer and one to hold the large amount of data (e.g., the elements
in an @{b}ARRAY@{ub}).  In fact, such declarations are merely @{b}PTR TO @{ub}@{fg shine}type@{fg text}@{b}@{ub}
declarations together with an initialisation of the pointer to the address
of some (statically) allocated memory to hold the data.  The following
example shows very similar declarations, with the difference being that in
the second case (using @{b}PTR@{ub}) only memory to hold the pointer values is
allocated.  The first case also allocates memory to hold the appropriate
size of array, object and E-string.

       DEF a[20]:ARRAY,   m:myobj,        s[10]:STRING
     
       DEF a:PTR TO CHAR, m:PTR TO myobj, s:PTR TO CHAR

   The pointers in the second case are not initialised by the declaration
and, therefore, they are not valid pointers.  This means that they should
not be dereferenced in any way, until they have been initialised to the
address of some allocated memory.  This usually involves dynamic
allocation of memory (see @{"Dynamic Allocation" Link "Dynamic Allocation"}).


@EndNode

@Node "Deallocation of Memory" "beginner.guide/Deallocation of Memory"
@Next "Dynamic Allocation"
@Prev "Static Allocation"
@Toc "Memory Allocation"

Deallocation of Memory
======================

   When memory is allocated it is, conceptually, marked as being `in use'.
This means that this piece of memory cannot be allocated again, so a
different piece will be allocated (if any is available) when the program
wants to allocate some more.  In this way, variables are allocated
different pieces of memory, and so their values can be distinct.  But
there is only a certain amount of memory available, and if it could not be
marked as `not in use' again it would soon run out (and the program would
come to a nasty end).  This is what @{fg shine}deallocation@{fg text} does: it marks
previously allocated memory as being `not in use' and so makes it
available for allocation again.  However, memory should be deallocated
only when it is actually no longer in use, and this is where things get a
bit complicated.

   Memory is such a vital resource in every computer that it is important
to use as little of it as necessary and to deallocate it whenever possible.
This is why a programming language like E handles most of the memory
allocation for variables.  The memory allocated for variables can be
automatically deallocated when it is no longer possible for the program to
use that variable.  However, this automatic deallocation is not useful for
global variables, since they can be used from any procedure and so can be
deallocated only when the program terminates.  A procedure's local
variables, on the other hand, are allocated when the procedure is called
but cannot be used after the procedure returns.  They can, therefore, be
deallocated when the procedure returns.

   Pointers, as always, can cause big problems.  The following example
shows why you need to be careful when using pointers as the return value
of a procedure.

     /* This is an example of what *NOT* to do */
     PROC fullname(first, last)
       DEF full[40]:STRING
       StrCopy(full, first)
       StrAdd(full, ' ')
       StrAdd(full, last)
     ENDPROC full
     
     PROC main()
       WriteF('Name is \s\n', fullname('Fred', 'Flintstone'))
     ENDPROC

On first sight this seems fine, and, in fact, it may even work correctly
if you run it once or twice (but be careful: it could crash your machine).
The problem is that the procedure @{b}fullname@{ub} returns the value of the local
variable @{b}full@{ub}, which is a pointer to some statically allocated memory for
the E-string and this memory will be deallocated when the procedure
returns.  This means that the return value of any call to @{b}fullname@{ub} is the
address of recently deallocated memory, so it is invalid to dereference it.
But the call to @{b}WriteF@{ub} does just that: it dereferences the result of
@{b}fullname@{ub} in order to print the E-string it points to.  This is a very
common problem, because it is such an easy thing to do.  The fact that it
may, on many occasions, appear to work makes it much harder to find, too.
The solution, in this case, is to use dynamic allocation (see
@{"Dynamic Allocation" Link "Dynamic Allocation"}).

   If you're still a bit sceptical that this really is a problem, try the
above @{b}fullname@{ub} procedure definition with either of these replacement @{b}main@{ub}
procedures, but be aware, again, that each one has the potential to crash
your machine.

     /* This might not print the correct string */
     PROC main()
       DEF f
       f:=fullname('Fred', 'Flintstone')
       WriteF('Name is \s\n', f)
     ENDPROC
     
     /* This will definitely print g instead of f */
     PROC main()
       DEF f, g
       f:=fullname('Fred', 'Flintstone')
       g:=fullname('Barney', 'Rubble')
       WriteF('Name is \s\n', f)
     ENDPROC

(The reason why things go wrong is outlined above, but the reasons why
each prints what it does is beyond the scope of this Guide.)


@EndNode

@Node "Dynamic Allocation" "beginner.guide/Dynamic Allocation"
@Next "NEW and END Operators"
@Prev "Deallocation of Memory"
@Toc "Memory Allocation"

Dynamic Allocation
==================

   @{fg shine}Dynamically@{fg text} allocated memory is any memory that is not statically
allocated.  To allocate memory dynamically you can use the @{b}List@{ub} and @{b}String@{ub}
functions, all flavours of @{b}New@{ub}, and the versatile @{b}NEW@{ub} operator.  But
because the memory is dynamically allocated it must be explicitly
deallocated when no longer needed.  In all the above cases, though, any
memory that is still allocated when the program terminates will be
deallocated automatically.

   Another way to allocate memory dynamically is to use the Amiga system
functions based on @{b}AllocMem@{ub}.  However, these functions require that the
memory allocated using them be deallocated (using functions like @{b}FreeMem@{ub})
before the program terminates, or else it will never be deallocated (not
until your machine is rebooted, anyway).  It is safer, therefore, to try
to use the E functions for dynamic allocation whenever possible.

   There are many reasons why you might want to use dynamic allocation,
and most of them involve initialisation of pointers.  For example, the
declarations in the section about static allocation can be extended to
give initialisations for the pointers declared in the second @{b}DEF@{ub} line (see
@{"Static Allocation" Link "Static Allocation"}).

       DEF a[20]:ARRAY,   m:myobj,        s[10]:STRING
     
       DEF a:PTR TO CHAR, m:PTR TO myobj, s:PTR TO CHAR
       a:=New(20)
       m:=New(SIZEOF myobj)
       s:=String(20)

These are initialisations to dynamically allocated memory, whereas the
first line of declarations initialise similar pointers to statically
allocated memory.  If these sections of code were part of a procedure
then, since they would now be local variables, there would be one other,
significant difference: the dynamically allocated memory would not
automatically be deallocated when the procedure returns, whereas the
statically allocated memory would.  This means that we can solve the
deallocation problem (see @{"Deallocation of Memory" Link "Deallocation of Memory"}).

     /* This is the correct way of doing it */
     PROC fullname(first, last)
       DEF full
       full:=String(40)
       StrCopy(full, first)
       StrAdd(full, ' ')
       StrAdd(full, last)
     ENDPROC full
     
     PROC main()
       DEF f, g
       WriteF('Name is \s\n', fullname('Fred', 'Flintstone'))
       f:=fullname('Fred', 'Flintstone')
       g:=fullname('Barney', 'Rubble')
       WriteF('Name is \s\n', f)
     ENDPROC

   The memory for the E-string pointed to by @{b}full@{ub} is now allocated
dynamically, using @{b}String@{ub}, and is not deallocated until the end of the
program.  This means that it is quite valid to pass the value of @{b}full@{ub} as
the result of the procedure @{b}fullname@{ub}, and it is quite valid to dereference
the result by printing it using @{b}WriteF@{ub}.  However, this has caused one last
problem: the memory is not deallocated until the end of the program, so is
potentially wasted since it could be used, for example, to hold the
results of subsequent calls.  Of course, the memory can be deallocated
only when the data it stores is no longer required.  The following
replacement @{b}main@{ub} procedure shows when you might want to deallocate the
E-string (using @{b}DisposeLink@{ub}).

     PROC main()
       DEF f, g
       f:=fullname('Fred', 'Flintstone')
       WriteF('Name is \s, f points to $\h\n', f, f)
     /* Try this with and without the next DisposeLink line */
       DisposeLink(f)
       g:=fullname('Barney', 'Rubble')
       WriteF('Name is \s, g points to $\h\n', g, g)
       DisposeLink(g)
     ENDPROC

   If you run this with the @{b}DisposeLink(f)@{ub} line you'll probably find that
@{b}g@{ub} will be a pointer to the same memory as @{b}f@{ub}.  This is because the call
to @{b}DisposeLink@{ub} has deallocated the memory pointed to by @{b}f@{ub}, so it can be
reused to store the E-string pointed to by @{b}g@{ub}.  If you comment out (or
delete) the @{b}DisposeLink@{ub} line, then you will find that @{b}f@{ub} and @{b}g@{ub} always point
to different memory.

   In some ways it is best to never do any deallocation, because of the
problems you can get into if you deallocate memory too early (i.e., before
you've finished with the data it contains).  Of course, it is safe (but
temporarily wasteful) to do this with the E dynamic allocation functions,
but it is very wasteful (and wrong) to do this with the Amiga system
functions like @{b}AllocMem@{ub}.

   Another benefit of using dynamic allocation is that the size of the
arrays, E-lists and E-strings that can be created can be the result of any
expression, so is not restricted to constant values.  (Remember that the
size given on @{b}ARRAY@{ub}, @{b}LIST@{ub} and @{b}STRING@{ub} declarations must be a constant.)
This means that the @{b}fullname@{ub} procedure can be made more efficient and
allocate only the amount of memory it needs for the E-string it creates.

     PROC fullname(first, last)
       DEF full
       /* The extra +1 is for the added space */
       full:=String(StrLen(first)+StrLen(last)+1)
       StrCopy(full, first)
       StrAdd(full, ' ')
       StrAdd(full, last)
     ENDPROC full

However, it may be very complicated or inefficient to calculate the
correct size.  In these cases, a quick, constant estimate might be better,
overall.

   The various functions for allocating memory dynamically have
corresponding functions for deallocating that memory.  The following table
shows some of the more common pairings.

     Allocation       Deallocation
     ------------------------------
     New              Dispose
     NewR             Dispose
     List             DisposeLink
     String           DisposeLink
     NEW              END
     FastNew          FastDispose
     AllocMem         FreeMem
     AllocVec         FreeVec
     AllocDosObject   FreeDosObject

@{b}NEW@{ub} and @{b}END@{ub} are versatile and powerful operators, discussed in the
following section.  The functions beginning with @{b}Alloc-@{ub} are Amiga system
functions and are paired with similarly suffixed functions with a @{b}Free-@{ub}
prefix.  See the `Rom Kernel Reference Manual' for more details.


@EndNode

@Node "NEW and END Operators" "beginner.guide/NEW and END Operators"
@Prev "Dynamic Allocation"
@Toc "Memory Allocation"

@{b}NEW@{ub} and @{b}END@{ub} Operators
=====================

   To help deal with dynamic allocation and deallocation of memory there
are two, powerful operators, @{b}NEW@{ub} and @{b}END@{ub}.  The @{b}NEW@{ub} operator is very
versatile, and similar in operation to the @{b}New@{ub} family of built-in
functions (see @{"System support functions" Link "System support functions"}).  The @{b}END@{ub} operator is the
deallocating complement of @{b}NEW@{ub} (so it is similar to the @{b}Dispose@{ub} family of
built-in functions).  The major difference between @{b}NEW@{ub} and the various
flavours of @{b}New@{ub} is that @{b}NEW@{ub} allocates memory based on the types of its
arguments.


 @{" Object and simple typed allocation " Link "Object and simple typed allocation"} 
 @{" Array allocation " Link "Array allocation"} 
 @{" List and typed list allocation " Link "List and typed list allocation"} 
 @{" OOP object allocation " Link "OOP object allocation"} 


@EndNode

@Node "Object and simple typed allocation" "beginner.guide/Object and simple typed allocation"
@Next "Array allocation"
@Toc "NEW and END Operators"

Object and simple typed allocation
----------------------------------

   The following sections of code are roughly equivalent and serve to show
the function of @{b}NEW@{ub}, and how it is closely related to @{b}NewR@{ub}.  (The @{fg shine}type@{fg text}
can be any object or simple type.)

       DEF p:PTR TO @{fg shine}type@{fg text}
       NEW p
     
       DEF p:PTR TO @{fg shine}type@{fg text}
       p:=NewR(SIZEOF @{fg shine}type@{fg text})

Notice that the use of @{b}NEW@{ub} is not like a function call, as there are no
parentheses around the parameter @{b}p@{ub}.  This is because @{b}NEW@{ub} is an operator
rather than a function.  It works differently from a function, since it
also needs to know the types of its arguments.  This means that the
declaration of @{b}p@{ub} is very important, since it governs how much memory is
allocated by @{b}NEW@{ub}.  The version using @{b}NewR@{ub} explicitly gives the amount of
memory to be allocated (using the @{b}SIZEOF@{ub} operator), so in this case the
declared type of @{b}p@{ub} is not so important for correct allocation.

   The next example shows how @{b}NEW@{ub} can be used to initialise several
pointers at once.  The second section of code is roughly equivalent, but
uses @{b}NewR@{ub}.  (Remember that the default type of a variable is @{b}LONG@{ub}, which
is actually @{b}PTR TO CHAR@{ub}.)

       DEF p:PTR TO LONG, q:PTR TO myobj, r
       NEW p, q, r
     
       DEF p:PTR TO LONG, q:PTR TO myobj, r
       p:=NewR(SIZEOF LONG)
       q:=NewR(SIZEOF myobj)
       r:=NewR(SIZEOF CHAR)

   These first two examples have shown the statement form of @{b}NEW@{ub}.  There
is also an expression form, which has one parameter and returns the
address of the newly allocated memory as well as initialising the argument
pointer to this address.

       DEF p:PTR TO myobj, q:PTR TO myobj
       q:=NEW p
     
       DEF p:PTR TO myobj, q:PTR TO myobj
       q:=(p:=NewR(SIZEOF @{fg shine}type@{fg text}))

This may not seem desperately useful, but it's also the way that @{b}NEW@{ub} is
used to allocate copies of lists and typed lists (see
@{"List and typed list allocation" Link "List and typed list allocation"}).

   To deallocate memory allocated using @{b}NEW@{ub} you use the @{b}END@{ub} statement with
the pointers that you want to deallocate.  To work properly, @{b}END@{ub} requires
that the type of each pointer matches the type used when it was allocated
with @{b}NEW@{ub}.  Failure to do this will result in an incorrect amount of memory
being deallocated, and this can cause many subtle problems in a program.
You must also be careful not to deallocate the same memory twice, and to
this end the pointers given to @{b}END@{ub} are re-initialised to @{b}NIL@{ub} after the
memory they point to is deallocated (it is quite safe to use @{b}END@{ub} with a
pointer which is @{b}NIL@{ub}).  This does not catch all problems, however, since
more than one pointer can point to the same piece of memory, as shown in
the example below.

       DEF p:PTR TO LONG, q:PTR TO LONG
       q:=NEW p
       p[]:=-24
       q[]:=613
       END p
       /* p is now NIL, but q is now invalid but not NIL */

   The first assignment initialises @{b}q@{ub} to be the same as @{b}p@{ub} (which is
initialised by @{b}NEW@{ub}).  @{i}Both@{ui} the next two assignments change the value
pointed to by @{i}both@{ui} @{b}p@{ub} and @{b}q@{ub}.  The memory allocated to store this value is
then deallocated, using @{b}END@{ub}, and this also sets @{b}p@{ub} to @{b}NIL@{ub}.  However, the
address stored in @{b}q@{ub} is not altered, and still points to the memory that
has just been deallocated.  This means that @{b}q@{ub} now has a plausible, but
invalid, pointer value.  The only thing that can safely be done with @{b}q@{ub} is
re-initialise it.  One of the @{i}worst@{ui} things that could be done is to use it
with @{b}END@{ub}, which would deallocate the same memory again, and potentially
crash your machine.  So, in summary, don't deallocate the same pointer
value more than once, and keep track of which variables point to the same
memory as others.

   Just as a use of @{b}NEW@{ub} has a simple (but rough) equivalent using @{b}NewR@{ub},
@{b}END@{ub} has an equivalent using @{b}Dispose@{ub}, as shown by the following
sections of code.

       END p
     
       IF p
         Dispose(p)
         p:=NIL
       ENDIF

In fact, it's a tiny bit more complicated than that, since OOP objects are
allocated and deallocated using @{b}NEW@{ub} and @{b}END@{ub} (see @{"Object Oriented E" Link "Object Oriented E"}).


@EndNode

@Node "Array allocation" "beginner.guide/Array allocation"
@Next "List and typed list allocation"
@Prev "Object and simple typed allocation"
@Toc "NEW and END Operators"

Array allocation
----------------

   Arrays can also be allocated using @{b}NEW@{ub}, and this works in a very
similar way to that outlined in the previous section.  The difference is
that the size of the array must also be supplied, in both the use of @{b}NEW@{ub}
and @{b}END@{ub}.  Of course, the size supplied to @{b}END@{ub} must be the same as the size
supplied to the appropriate use of @{b}NEW@{ub}.  All this extra effort also gains
you the ability to create an array of a size which is not a constant
(unlike variables of type @{b}ARRAY@{ub}).  This means that the size supplied to
@{b}NEW@{ub} and @{b}END@{ub} can be the result of an arbitrary expression.

       DEF a:PTR TO LONG, b:PTR TO myobj, s
       NEW a[10]  /* A dynamic array of LONG  */
       s:=my_random(20)
       NEW b[s]   /* A dynamic array of myobj */
       /* ...some other code... */
       END a[10], b[s]

The @{b}my_random@{ub} function stands for some arbitrary calculation, to show that
@{b}s@{ub} does not have to be a constant.  This form of @{b}NEW@{ub} can also be used as an
expression, as before.


@EndNode

@Node "List and typed list allocation" "beginner.guide/List and typed list allocation"
@Next "OOP object allocation"
@Prev "Array allocation"
@Toc "NEW and END Operators"

List and typed list allocation
------------------------------

   Lists and typed lists are usually static data, but @{b}NEW@{ub} can be used to
create dynamically allocated versions.  This form of @{b}NEW@{ub} can be used only
as an expression, and it takes the list (or typed list) as its argument
and returns the address of the dynamically allocated copy of the list.
Deallocation of the memory allocated in this way is a bit more complicated
than before, but you can, of course, let it be deallocated automatically
at the end of the program.

   The following example shows how simple it is to use @{b}NEW@{ub} to cure the
static data problem described previously (see @{"Static data" Link "Static data"}).  The
difference from the original, incorrect program is very subtle.

     PROC main()
       DEF i, a[10]:ARRAY OF LONG, p:PTR TO LONG
       FOR i:=0 TO 9
         a[i]:=NEW [1, i, i*i]
           /* a[i] is now dynamically allocated */
       ENDFOR
       FOR i:=0 TO 9
         p:=a[i]
         WriteF('a[\d] is an array at address \d\n', i, p)
         WriteF('  and the second element is \d\n', p[1])
       ENDFOR
     ENDPROC

The minor alteration is to prefix the list with @{b}NEW@{ub}, thereby making the
list dynamic.  This means that each @{b}a[i]@{ub} is now a different list, rather
than the same, static list of the original version of the program.

   Typed lists are allocated in a similar way, and the following example
also shows how to deallocate this memory.  Basically, you need to know how
long the new array is (i.e., how many elements there are), since a typed
list is really just an initialised array.  You can then deallocate it like
a normal array, remembering to use an appropriately typed pointer.
Object-typed lists are restricted (when used with @{b}NEW@{ub}) to an array of at
most one object, so is useful only for allocating an initialised object
(not really an array).  Notice how, in the following code, the pointer @{b}q@{ub}
can be treated both as an object and as an array of one object (see
@{"Element selection and element types" Link "Element selection and element types"}).

     OBJECT myobj
       x:INT, y:LONG, z:INT
     ENDOBJECT
     
     PROC main()
       DEF p:PTR TO INT, q:PTR TO myobj
       p:=NEW [1, 9, 3, 7, 6]:INT
       q:=NEW [1, 2]:myobj
       WriteF('Last element in array p is \d\n', p[4])
       WriteF('Object q is x=\d, y=\d, z=\d\n',
              q.x,   q.y,   q.z)
       WriteF('Array q is q[0].x=\d, q[0].y=\d, q[0].z=\d\n',
              q[].x, q[].y, q[].z)
       END p[5], q
     ENDPROC

The dynamically allocated version of an object-typed list differs from the
static version in another way: it always has memory allocated for a whole
number of objects, so a partially initialised object is padded with zero
elements.  The static version does not allocate this extra padding, so you
must be careful not to access any element beyond those mentioned in the
list.

   The deallocation of @{b}NEW@{ub} copies of normal lists can, as ever, be left to
be done automatically at the end of the program.  If you want to
deallocate them before this time you must use the function
@{b}FastDisposeList@{ub}, passing the address of the list as the only argument.
You @{i}must@{ui} not use @{b}END@{ub} or any other method of deallocation.  @{b}FastDisposeList@{ub}
is the only safe way of deallocating lists allocated using @{b}NEW@{ub}.


@EndNode

@Node "OOP object allocation" "beginner.guide/OOP object allocation"
@Prev "List and typed list allocation"
@Toc "NEW and END Operators"

OOP object allocation
---------------------

   Currently, the only way to create OOP objects in E is to use @{b}NEW@{ub} and
the only safe way to destroy them is to use @{b}END@{ub}.  This is probably the
most common use of @{b}NEW@{ub} and @{b}END@{ub} and is described in detail later (see
@{"Objects in E" Link "Objects in E"}).


@EndNode

@Node "Floating-Point Numbers" "beginner.guide/Floating-Point Numbers"
@Next "Recursion"
@Prev "Memory Allocation"
@Toc "Main"

Floating-Point Numbers
**********************

   @{fg shine}Floating-point@{fg text} or @{fg shine}real@{fg text} numbers can be used to represent both very
small fractions and very large numbers.  However, unlike a @{b}LONG@{ub} which can
hold every integer in a certain range (see @{"Variable types" Link "Variable types"}), floating-point
numbers have limited @{fg shine}accuracy@{fg text}.  Be warned, though: using floating-point
arithmetic in E is quite complicated and most problems can be solved
without using floating-point numbers, so you may wish to skip this chapter
until you really need to use them.


 @{" Floating-Point Values " Link "Floating-Point Values"} 
 @{" Floating-Point Calculations " Link "Floating-Point Calculations"} 
 @{" Floating-Point Functions " Link "Floating-Point Functions"} 
 @{" Accuracy and Range " Link "Accuracy and Range"} 


@EndNode

@Node "Floating-Point Values" "beginner.guide/Floating-Point Values"
@Next "Floating-Point Calculations"
@Toc "Floating-Point Numbers"

Floating-Point Values
=====================

   Floating-point values in E are written just like you might expect and
are stored in @{b}LONG@{ub} variables:

       DEF x
       x:=3.75
       x:=-0.0000367
       x:=275.0

You must remember to use a decimal point (without any spaces around it) in
the number if you want it to be considered a floating-point number, and
this is why a trailing @{b}.0@{ub} was used on the number in the last assignment.
At present you can't express every floating-point value in this way; the
compiler may complain that the value does not fit in 32-bits if you try to
use more than about nine digits in a single number.  You can, however, use
the various floating-point maths functions to calculate any value you want
(see @{"Floating-Point Functions" Link "Floating-Point Functions"}).


@EndNode

@Node "Floating-Point Calculations" "beginner.guide/Floating-Point Calculations"
@Next "Floating-Point Functions"
@Prev "Floating-Point Values"
@Toc "Floating-Point Numbers"

Floating-Point Calculations
===========================

   Since a floating-point number is stored in a @{b}LONG@{ub} variable it would
normally be interpreted as an integer, and this interpretation will
generally not give a number anything like the intended floating-point
number.  To use floating-point numbers in expressions you must use the
(rather complicated) floating-point conversion operator, which is the @{b}!@{ub}
character.  This converts expressions and the normal maths and comparison
operators to and from floating-point.

   All expressions are, by default, integer expressions.  That is, they
represent @{b}LONG@{ub} integer values, rather than floating-point values.  The
first time a @{b}!@{ub} occurs in an expression the value of the expression so far
is converted to floating-point and all the operators and variables after
this point are considered floating-point.  The next time it occurs the
(floating-point) value of the expression so far is converted to an
integer, and the following operators and variables are considered integer
again.  You can use @{b}!@{ub} as often as necessary within an expression.  Parts
of an expression in parentheses are treated as separate expressions, so
are, by default, integer expressions (this, includes function call
arguments).

   The integer/floating-point conversions performed by @{b}!@{ub} are not simple.
They involve rounding and also bounding.  Conversion, for example, from
integer to floating-point and back again will generally not result in the
original integer value.

   Here's a few commented examples, where @{b}f@{ub} always holds a floating-point
number, and @{b}i@{ub} and @{b}j@{ub} always hold integers:

       DEF f, i, j
       i:=1
       f:=1.0
       f:=i!  -> i converted to floating-point (1.0)
       f:=6.2
       i:=!f! -> the expression f is floating-point,
              -> then converted to integer (6)

In the first assignment, the integer value one is assigned to @{b}i@{ub}.  In the
second, the floating-point value 1.0 is assigned to @{b}f@{ub}.  The expression on
the right-hand side of third assignment is considered to be an integer
until the @{b}!@{ub} is met, at which point it is converted to the nearest
floating-point value.  So, @{b}f@{ub} is assigned the floating-point value of one
(i.e., 1.0), just like it is by the second assignment.  The expression in
the final assignment needs to start off as floating-point in order to
interpret the value stored in @{b}f@{ub} as floating-point.  The expression
finishes by converting back to integer.  The overall result is to turn the
floating-point value of @{b}f@{ub} into the nearest integer (in this case, six).

   The assignments below are more complicated, but should be
straight-forward to follow.  Again, @{b}f@{ub} always holds a floating-point
number, and @{b}i@{ub} and @{b}j@{ub} always hold integers.

       f:=!f*f -> the whole expression is floating-point,
               -> and f is squared (6.2*6.2)
       f:=!f*(i!) -> the whole expression is floating-point,
                  -> i is converted to floating-point and
                  -> multiplied by f
       j:=!f/(i!)! -> the whole division is floating-point,
                   -> with the result converted to integer
       j:=!f!/i -> floating-point f is converted to integer
                -> and is (integer) divided by i
       IF !f<230.0 THEN RETURN 0  -> floating-point comparison <
       IF !f>(i!)  THEN RETURN 0  -> i converted to floating-point,
                                  -> then compared to f

If the @{b}!@{ub} were omitted from the first assignment, then not only would the
value in @{b}f@{ub} be interpreted (incorrectly) as integer, but the multiplication
performed would be integer multiplication, rather than floating-point.  In
the second assignment, the parentheses around the expression involving @{b}i@{ub}
are crucial.  Without the parentheses the value stored in @{b}i@{ub} would be
interpreted as floating-point.  This would be wrong because @{b}i@{ub} actually
stores an integer value, so parentheses are used to start a new expression
(which defaults to being integer).  The value of @{b}i@{ub} is then interpreted
correctly, and finally converted to floating-point (by the @{b}!@{ub} just before
the closing parenthesis).  The (floating-point) multiplication then takes
place with two floating-point values, and the result is stored in @{b}f@{ub}.  In
the last two assignments (using division), @{b}j@{ub} is assigned roughly the same
value.  However, the expression in the first assignment allows for greater
accuracy, since it uses floating-point division.  This means the result
will be rounded, whereas it is truncated when integer division is used.

   One important thing to know about floating-point numbers in E is that
the following assignments store the same value in @{b}g@{ub} (again, @{b}f@{ub} stores a
floating-point number).  This is because no computation is performed and
no conversion happens: the value in @{b}f@{ub} is simply copied to @{b}g@{ub}.  This is
especially important for function calls, as we shall see in the next
section.  Strictly speaking, however, the second version is better, since
it shows (to the reader of the code) that the value in @{b}f@{ub} is meant to be
floating-point.

       g:=f
       g:=!f


@EndNode

@Node "Floating-Point Functions" "beginner.guide/Floating-Point Functions"
@Next "Accuracy and Range"
@Prev "Floating-Point Calculations"
@Toc "Floating-Point Numbers"

Floating-Point Functions
========================

   There are functions for formatting floating-point numbers to E-strings
(so that they can be printed) and for decoding floating-point numbers from
strings.  There are also a number of built-in, floating-point functions
which compute some of the less common mathematical functions, such as the
various trigonometric functions.

@{b}RealVal(@{ub}@{fg shine}string@{fg text}@{b})@{ub}
     This works in a similar way to @{b}Val@{ub} for extracting integers from a
     string.  The decoded floating-point value is returned as the regular
     return value, and the number of characters of @{fg shine}string@{fg text} that were read
     to make the number is returned as the first optional return value.
     If a floating-point value could not be decoded from the string then
     zero is returned as the optional return value and the regular return
     value will be zero (i.e., 0.0).

@{b}RealF(@{ub}@{fg shine}e-string@{fg text}@{b},@{ub}@{fg shine}float@{fg text}@{b},@{ub}@{fg shine}digits@{fg text}@{b})@{ub}
     Converts the floating-point value @{b}float@{ub} into a string which is stored
     in @{fg shine}e-string@{fg text}.  The number of digits to use after the decimal point
     is specified by @{fg shine}digits@{fg text}, which can be zero to eight.  The
     floating-point value is rounded to the specified number of digits.  A
     value of zero for @{fg shine}digits@{fg text} gives a result with no fractional part and
     no decimal point.  The @{fg shine}e-string@{fg text} is returned by this function, and
     this makes it easy to use with @{b}WriteF@{ub}.

          PROC main()
            DEF s[20]:STRING, f, i
            f:=21.60539
            FOR i:=0 TO 8
              WriteF('f is \s (using digits=\d)\n', RealF(s, f, i), i)
            ENDFOR
          ENDPROC

     Notice that the floating-point argument, @{b}f@{ub}, to @{b}RealF@{ub} does not need a
     leading @{b}!@{ub} because we are simply passing its value and not performing
     a computation with it.  The program should generate the following
     output:

          f is 22 (using digits=0)
          f is 21.6 (using digits=1)
          f is 21.61 (using digits=2)
          f is 21.605 (using digits=3)
          f is 21.6054 (using digits=4)
          f is 21.60539 (using digits=5)
          f is 21.605390 (using digits=6)
          f is 21.6053900 (using digits=7)
          f is 21.60539000 (using digits=8)

@{b}Fsin(@{ub}@{fg shine}float@{fg text}@{b})@{ub}, @{b}Fcos(@{ub}@{fg shine}float@{fg text}@{b})@{ub}, @{b}Ftan(@{ub}@{fg shine}float@{fg text}@{b})@{ub}
     These compute the sine, cosine and tangent (respectively) of the
     supplied @{fg shine}float@{fg text} angle, which is specified in radians.

@{b}Fabs(@{ub}@{fg shine}float@{fg text}@{b})@{ub}
     Returns the absolute value of @{fg shine}float@{fg text}, much like @{b}Abs@{ub} does for
     integers.

@{b}Ffloor(@{ub}@{fg shine}float@{fg text}@{b})@{ub}, @{b}Fceil(@{ub}@{fg shine}float@{fg text}@{b})@{ub}
     The @{b}Ffloor@{ub} function rounds a floating-point value down to the
     nearest, whole floating-point value.  The @{b}Fceil@{ub} function rounds it up.

@{b}Fsqrt(@{ub}@{fg shine}float@{fg text}@{b})@{ub}
     Returns the square root of @{fg shine}float@{fg text}.

@{b}Fpow(@{ub}@{fg shine}x@{fg text}@{b},@{ub}@{fg shine}y@{fg text}@{b})@{ub}, @{b}Fexp(@{ub}@{fg shine}float@{fg text}@{b})@{ub}
     The @{b}Fpow@{ub} function returns the value of @{fg shine}x@{fg text} raised to the power of @{fg shine}y@{fg text}
     (which are both floating-point values).  The @{b}Fexp@{ub} function returns
     the value of e raised to the power of @{fg shine}float@{fg text}, where e is the
     mathematically special value (roughly 2.718282).  `Raising to a
     power' is known as @{fg shine}exponentiation@{fg text}.

@{b}Flog10(@{ub}@{fg shine}float@{fg text}@{b})@{ub}, @{b}Flog(@{ub}@{fg shine}float@{fg text}@{b})@{ub}
     The @{b}Flog10@{ub} function returns the log to base ten of @{fg shine}float@{fg text} (the
     @{fg shine}common logarithm@{fg text}).  The @{b}Flog@{ub} function returns the log to base e of
     @{fg shine}float@{fg text} (the @{fg shine}natural logarithm@{fg text}).  @{b}Flog10@{ub} and @{b}Fpow@{ub} are linked in the
     following way (ignoring floating-point inaccuracies):

            x = Fpow(10.0, Flog10(x))

     @{b}Flog@{ub} and @{b}Fexp@{ub} are similarly related (@{b}Fexp@{ub} could be used again, using
     2.718282 as the first argument in place of 10.0).

            x = Fexp(Flog(x))

   Here's a small program which uses a few of the above functions, and
shows how to define functions which use and/or return floating-point
values.

     DEF f, i, s[20]:STRING
     
     PROC print_float()
       WriteF('\tf is \s\n', RealF(s, !f, 8))
     ENDPROC
     
     PROC print_both()
       WriteF('\ti is \d, ', i)
       print_float()
     ENDPROC
     
     /* Square a float */
     PROC square_float(f) IS !f*f
     
     /* Square an integer */
     PROC square_integer(i) IS i*i
     
     /* Converts a float to an integer */
     PROC convert_to_integer(f) IS Val(RealF(s, !f, 0))
     
     /* Converts an integer to a float */
     PROC convert_to_float(i) IS RealVal(StringF(s, '\d', i))
     
     /* This should be the same as Ftan */
     PROC my_tan(f) IS !Fsin(!f)/Fcos(!f)
     
     /* This should show float inaccuracies */
     PROC inaccurate(f) IS Fexp(Flog(!f))
     
     PROC main()
       WriteF('Next 2 lines should be the same\n')
       f:=2.7; i:=!f!
       print_both()
       f:=2.7; i:=convert_to_integer(!f)
       print_both()
     
       WriteF('Next 2 lines should be the same\n')
       i:=10;  f:=i!
       print_both()
       i:=10;  f:=convert_to_float(i)
       print_both()
     
       WriteF('f and i should be the same\n')
       i:=square_integer(i)
       f:=square_float(f)
       print_both()
     
       WriteF('Next 2 lines should be the same\n')
       f:=Ftan(.8)
       print_float()
       f:=my_tan(.8)
       print_float()
     
       WriteF('Next 2 lines should be the same\n')
       f:=.35
       print_float()
       f:=inaccurate(f)
       print_float()
     ENDPROC

The @{b}convert_to_integer@{ub} and @{b}convert_to_float@{ub} functions perform similar
conversions to those done by @{b}!@{ub} when it occurs in an expression.  To make
things more explicit, there are a lot of unnecessary uses of @{b}!@{ub}, and these
are when @{b}f@{ub} is passed directly as a parameter to a function (in these
cases, the @{b}!@{ub} could safely be omitted).  All of the examples have the
potential to give different results where they ought to give the same, and
this is due to the inaccuracy of floating-point numbers.  The last example
has been carefully chosen to show this.


@EndNode

@Node "Accuracy and Range" "beginner.guide/Accuracy and Range"
@Prev "Floating-Point Functions"
@Toc "Floating-Point Numbers"

Accuracy and Range
==================

   A floating-point number is just another 32-bit value, so can be stored
in @{b}LONG@{ub} variables.  It's just the interpretation of the 32-bits which
makes them different.  A floating-point number can range from numbers as
small as 1.3E-38 to numbers as large as 3.4E+38 (that's very small and
very large if you don't understand the scientific notation!).  However,
not every number in this range can @{fg shine}accurately@{fg text} be represented, since the
number of significant digits is roughly eight.

   Accuracy is an important consideration when trying to compare two
floating-point numbers and when combining floating-point values after
dividing them.  It is usually best to check that a floating-point value is
in a small range of values, rather than just a particular value.  And when
combining values, allow for a small amount of error due to rounding etc.
See the `Reference Manual' for more details about the implementation of
floating-point numbers.


@EndNode

@Node "Recursion" "beginner.guide/Recursion"
@Next "Object Oriented E"
@Prev "Floating-Point Numbers"
@Toc "Main"

Recursion
*********

   A @{fg shine}recursive@{fg text} function is very much like a function which uses a loop.
Basically, a @{fg shine}recursive@{fg text} function calls itself (usually after some
manipulation of data) rather than iterating a bit of code using a loop.
There are also recursive types, which are objects with elements which have
the object type (in E these would be pointers to objects).  We've already
seen a recursive type: linked lists, where each element in the list
contains a pointer to the next element (see @{"Linked Lists" Link "Linked Lists"}).

   Recursive definitions are normally much more understandable than an
equivalent iterative definition, and it's usually easier to use recursive
functions to manipulate this data from a recursive type.  However,
recursion is by no means a simple topic.  Read on at your own peril!


 @{" Factorial Example " Link "Factorial Example"} 
 @{" Mutual Recursion " Link "Mutual Recursion"} 
 @{" Binary Trees " Link "Binary Trees"} 
 @{" Stack (and Crashing) " Link "Stack (and Crashing)"} 
 @{" Stack and Exceptions " Link "Stack and Exceptions"} 


@EndNode

@Node "Factorial Example" "beginner.guide/Factorial Example"
@Next "Mutual Recursion"
@Toc "Recursion"

Factorial Example
=================

   The normal example for a recursive definition is the factorial
function, so let's not be different.  In school mathematics the symbol @{b}!@{ub}
is used after a number to denote the factorial of that number (and only
positive integers have factorials).  n! is n-factorial, which is defined
as follows:

     n! = n * (n-1) * (n-2) * ... * 1     (for n >= 1)

So, 4! is 4*3*2*1, which is 24.  And, 5! is 5*4*3*2*1, which is 120.

   Here's the iterative definition of a factorial function (we'll @{b}Raise@{ub} an
exception is the number is not positive, but you can safely leave this
check out if you are sure the function will be called only with positive
numbers):

     PROC fact_iter(n)
       DEF i, result=1
       IF n<=0 THEN Raise("FACT")
       FOR i:=1 TO n
         result:=result*i
       ENDFOR
     ENDPROC result

We've used a @{b}FOR@{ub} loop to generate the numbers one to @{b}n@{ub} (the parameter to
the @{b}fact_iter@{ub}), and @{b}result@{ub} holds the intermediate and final results.  The
final result is returned, so check that @{b}fact_iter(4)@{ub} returns 24 and
@{b}fact_iter(5)@{ub} returns 120 using a @{b}main@{ub} procedure something like this:

     PROC main()
       WriteF('4! is \d\n5! is\d\n', fact_iter(4), fact_iter(5))
     ENDPROC

   If you're really observant you might have noticed that 5! is 5*4!, and,
in general, n! is n*(n-1)!.  This is our first glimpse of a recursive
definition--we can define the factorial function in terms of itself.  The
real definition of factorial is (the reason why this is the real
definition is because the `...' in the previous definition is not
sufficiently precise for a mathematical definition):

     1! = 1
     n! = n * (n-1)!    (for n > 1)

Notice that there are now two cases to consider.  The first case is called
the @{fg shine}base@{fg text} case and gives an easily calculated value (i.e., no recursion
is used).  The second case is the @{fg shine}recursive@{fg text} case and gives a definition
in terms of a number nearer the base case (i.e., (n-1) is nearer 1 than n,
for n>1).  The normal problem people get into when using recursion is they
forget the base case.  Without the base case the definition is meaningless.
Without a base case in a recursive program the machine is likely to crash!
(See @{"Stack (and Crashing)" Link "Stack (and Crashing)"}.)

   We can now define the recursive version of the @{b}fact_iter@{ub} function
(again, we'll use a @{b}Raise@{ub} if the number parameter is not positive):

     PROC fact_rec(n)
       IF n=1
         RETURN 1
       ELSEIF n>=2
         RETURN n*fact_rec(n-1)
       ELSE
         Raise("FACT")
       ENDIF
     ENDPROC

Notice how this looks just like the mathematical definition, and is nice
and compact.  We can even make a one-line function definition (if we omit
the check on the parameter being positive):

     PROC fact_rec2(n) RETURN IF n=1 THEN 1 ELSE n*fact_rec2(n-1)

You might be tempted to omit the base case and write something like this:

     /* Don't do this! */
     PROC fact_bad(n) RETURN n*fact_bad(n-1)

The problem is the recursion will never end.  The function @{b}fact_bad@{ub} will
be called with every number from @{b}n@{ub} to zero and then all the negative
integers.  A value will never be returned, and the machine will crash
after a while.  The precise reason why it will crash is given later (see
@{"Stack (and Crashing)" Link "Stack (and Crashing)"}).


@EndNode

@Node "Mutual Recursion" "beginner.guide/Mutual Recursion"
@Next "Binary Trees"
@Prev "Factorial Example"
@Toc "Recursion"

Mutual Recursion
================

   In the previous section we saw the function @{b}fact_rec@{ub} which called
itself.  If you have two functions, @{b}fun1@{ub} and @{b}fun2@{ub}, and @{b}fun1@{ub} calls @{b}fun2@{ub},
and @{b}fun2@{ub} calls @{b}fun1@{ub}, then this pair of functions are @{fg shine}mutually@{fg text} recursive.
This extends to any amount of functions linked in this way.

   This is a rather contrived example of a pair of mutually recursive
functions.

     PROC f(n)
       IF n=1
         RETURN 1
       ELSEIF n>=2
         RETURN n*g(n-1)
       ELSE
         Raise("F")
       ENDIF
     ENDPROC
     
     PROC g(n)
       IF n=1
         RETURN 2*1
       ELSEIF n>=2
         RETURN 2*n*f(n-1)
       ELSE
         Raise("G")
       ENDIF
     ENDPROC

Both functions are very similar to the @{b}fact_rec@{ub} function, but @{b}g@{ub} returns
double the normal values.  The overall effect is that every other value in
long version of the multiplication is doubled.  So, @{b}f(n)@{ub} computes
n*(2*(n-1))*(n-2)*(2*(n-3))*...*2 which probably isn't all that
interesting.


@EndNode

@Node "Binary Trees" "beginner.guide/Binary Trees"
@Next "Stack (and Crashing)"
@Prev "Mutual Recursion"
@Toc "Recursion"

Binary Trees
============

   This is an example of a recursive type and the effect it has on
functions which manipulate this type of data.  A @{fg shine}binary tree@{fg text} is like a
linked list, but instead of each element containing only one link to
another element there are two links in each element of a binary tree
(which point to smaller trees called @{fg shine}branches@{fg text}).  The first link points
to the @{i}left@{ui} branch and the second points to the @{i}right@{ui} branch.  Each
element of the tree is called a @{fg shine}node@{fg text} and there are two kinds of special
node: the start point, called the @{fg shine}root@{fg text} of the tree (like the head of a
list), and the nodes which do not have left or right branches (i.e., @{b}NIL@{ub}
pointers for both links), called @{fg shine}leaves@{fg text}.  Every node of the tree
contains some kind of data (just as the linked lists contained an E-string
or E-list in each element).  The following diagram illustrates a small
tree.

                 +------+
                 | Root |
                 +--*---+
                   / \
             Left /   \ Right
                 /     \
         +------*       *------+
         | Node |       | Node |
         +--*---+       +--*---+
           /              / \
     Left /         Left /   \ Right
         /              /     \
     +--*---+     +----*-+   +-*----+
     | Leaf |     | Leaf |   | Leaf |
     +------+     +------+   +------+

Notice that a node might have only one branch (it doesn't have to have
both the left and the right).  Also, the leaves on the example were all at
the same level, but this doesn't have to be the case.  Any of the leaves
could easily have been a node which had a lot of nodes branching off it.

   So, how can a tree structure like this be written as an E object?
Well, the general outline is this:

     OBJECT tree
       data
       left:PTR TO tree, right:PTR TO tree
     ENDOBJECT

The @{b}left@{ub} and @{b}right@{ub} elements are pointers to the left and right branches
(which will be @{b}tree@{ub} objects, too).  The @{b}data@{ub} element is some data for each
node.  This could equally well be a pointer, an @{b}ARRAY@{ub} or a number of
different data elements.

   So, what use can be made of such a tree?  Well, a common use is for
holding a sorted collection of data that needs to be able to have elements
added quickly.  As an example, the data at each node could be an integer,
so a tree of this kind could hold a sorted set of integers.  To make the
tree sorted, constraints must be placed on the left and right branches of
a node.  The left branch should contain only nodes with data that is @{i}less@{ui}
than the parent node's data, and, similarly, the right branch should
contain only nodes with data that is @{i}greater@{ui}.  Nodes with the same data
could be included in one of the branches, but for our example we'll
disallow them.  We are now ready to write some functions to manipulate our
tree.

   The first function is one which starts off a new set of integers (i.e.,
begins a new tree).  This should take an integer as a parameter and return
a pointer to the root node of new tree (with the integer as that node's
data).

     PROC new_set(int)
       DEF root:PTR TO tree
       NEW root
       root.data:=int
     ENDPROC root

The memory for the new tree element must be allocated dynamically, so this
is a good example of a use of @{b}NEW@{ub}.  Since @{b}NEW@{ub} clears the memory it
allocates all elements of the new object will be zero.  In particular, the
@{b}left@{ub} and @{b}right@{ub} pointers will be @{b}NIL@{ub}, so the root node will also be a leaf.
If the @{b}NEW@{ub} fails a @{b}"MEM"@{ub} exception is raised; otherwise the data is set to
the supplied value and a pointer to the root node is returned.

   To add a new integer to such a set we need to find the appropriate
position to insert it and set the left and right branches correctly.  This
is because if the integer is new to the set it will be added as a new
leaf, and so one of the existing nodes will change its left or right
branch.

     PROC add(i, set:PTR TO tree)
       IF set=NIL
         RETURN new_set(i)
       ELSE
         IF i<set.data
           set.left:=add(i, set.left)
         ELSEIF i>set.data
           set.right:=add(i, set.right)
         ENDIF
         RETURN set
       ENDIF
     ENDPROC

This function returns a pointer to the set to which it added the integer.
If this set was initially empty a new set is created; otherwise the
original pointer is returned.  The appropriate branches are corrected as
the search progresses.  Only the last assignment to the left or right
branch is significant (all others do not change the value of the pointer),
since it is this assignment that adds the new leaf.  Here's an iterative
version of this function:

     PROC add_iter(i, set:PTR TO tree)
       DEF node:PTR TO tree
       IF set=NIL
         RETURN new_set(i)
       ELSE
         node:=set
         LOOP
           IF i<node.data
             IF node.left=NIL
               node.left:=new_set(i)
               RETURN set
             ELSE
               node:=node.left
             ENDIF
           ELSEIF i>node.data
             IF node.right=NIL
               node.right:=new_set(i)
               RETURN set
             ELSE
               node:=node.right
             ENDIF
           ELSE
             RETURN set
           ENDIF
         ENDLOOP
       ENDIF
     ENDPROC

As you can see, it's quite a bit messier.  Recursive functions work well
with manipulation of recursive types.

   Another really neat example is printing the contents of the set.  It's
deceptively simple:

     PROC show(set:PTR TO tree)
       IF set<>NIL
         show(set.left)
         WriteF('\d ', set.data)
         show(set.right)
       ENDIF
     ENDPROC

The integers in the nodes will get printed in order (providing they were
added using the @{b}add@{ub} function).  The left-hand nodes contain the smallest
elements so the data they contain is printed first, followed by the data
at the current node, and then that in the right-hand nodes.  Try writing
an iterative version of this function if you fancy a really tough problem.

   Putting everything together, here's a @{b}main@{ub} procedure which can be used
to test the above functions:

     PROC main() HANDLE
       DEF s, i, j
       Rnd(-999999)    /* Initialise seed */
       s:=new_set(10)  /* Initialise set s to contain the number 10 */
       WriteF('Input:\n')
       FOR i:=1 TO 50  /* Generate 50 random numbers and add them to set s */
         j:=Rnd(100)
         add(j, s)
         WriteF('\d ',j)
       ENDFOR
       WriteF('\nOutput:\n')
       show(s)         /* Show the contents of the (sorted) set s */
       WriteF('\n')
     EXCEPT
       IF exception="NEW" THEN WriteF('Ran out of memory\n')
     ENDPROC


@EndNode

@Node "Stack (and Crashing)" "beginner.guide/Stack (and Crashing)"
@Next "Stack and Exceptions"
@Prev "Binary Trees"
@Toc "Recursion"

Stack (and Crashing)
====================

   When you call a procedure you use up a bit of the program's @{fg shine}stack@{fg text}.
The stack is used to keep track of procedures in a program which haven't
finished, and real problems can arise when the stack space runs out.
Normally, the amount of stack available to each program is sufficient,
since the E compiler handles all the fiddly bits quite well.  However,
programs which use a lot of recursion can quite easily run out of stack.

   For example, the @{b}fact_rec(10)@{ub} will need enough stack for ten calls of
@{b}fact_rec@{ub}, nine of which are recursively called.  This is because each call
does not finish until the return value has been computed, so all recursive
calls up to @{b}fact_rec(1)@{ub} need to be kept on the stack until @{b}fact_rec(1)@{ub}
returns one.  Then each procedure will be taken off the stack as they
finish.  If you try to compute @{b}fact_rec(40000)@{ub}, not only will this take a
long time, but it will probably run out of stack space.  When it does run
out of stack, the machine will probably crash or do other weird things.
The iterative version, @{b}fact_iter@{ub} does not have these problems, since it
only takes one procedure call to calculate a factorial using this function.

   If there is the possibility of running out of stack space you can use
the @{b}FreeStack@{ub} (built-in) function call (see @{"System support functions" Link "System support functions"}).
This returns the amount of free stack space.  If it drops below about 1KB
then you might like to stop the recursion or whatever else is using up the
stack.  Also, you can specify amount of stack your program gets (and
override what the compiler might decide is appropriate) using the @{b}OPT
STACK@{ub} option.  See the `Reference Manual' for more details on E's
stack organisation.


@EndNode

@Node "Stack and Exceptions" "beginner.guide/Stack and Exceptions"
@Prev "Stack (and Crashing)"
@Toc "Recursion"

Stack and Exceptions
====================

   The concept `recent' used earlier is connected with the stack (see
@{"Raising an Exception" Link "Raising an Exception"}).  A recent procedure is one which is on the stack,
the most recent being the current procedure.  So, when @{b}Raise@{ub} is called it
looks through the stack until it finds a procedure with an exception
handler.  That handler will then be used, and all procedures before the
selected one on the stack are taken off the stack.

   Therefore, a recursive function with an exception handler can use @{b}Raise@{ub}
in the handler to call the handler in the previous (recursive) call of the
function.  So anything that has been recursively allocated can be
`recursively' deallocated by exception handlers.  This is a very powerful
and important feature of exception handlers.


@EndNode

@Node "Object Oriented E" "beginner.guide/Object Oriented E"
@Next "Introduction to the Examples"
@Prev "Recursion"
@Toc "Main"

Object Oriented E
*****************

   The Object Oriented Programming (OOP) aspects of E are covered in this
chapter.  Don't worry if you don't know the OOP buzz words like `object',
`method' and `inheritance': these terms are explained in the OOP
introduction, below.  (For some reason, computer science uses strange
words to cloak simple concepts in secrecy.)


 @{" OOP Introduction " Link "OOP Introduction"} 
 @{" Objects in E " Link "Objects in E"} 
 @{" Methods in E " Link "Methods in E"} 
 @{" Inheritance in E " Link "Inheritance in E"} 
 @{" Data-Hiding in E " Link "Data-Hiding in E"} 


@EndNode

@Node "OOP Introduction" "beginner.guide/OOP Introduction"
@Next "Objects in E"
@Toc "Object Oriented E"

OOP Introduction
================

   `Object Oriented Programming' is the name given to a collection of
programming techniques that are meant to speed up development and ease
maintenance of large programs.  These techniques have been around for a
long time, but it is only recently that languages that explicitly support
them have become popular.  You do not @{i}need@{ui} to use a language that supports
OOP to program in an Object Oriented way; it's just a bit simpler if you
do!


 @{" Classes and methods " Link "Classes and methods"} 
 @{" Example class " Link "Example class"} 
 @{" Inheritance " Link "Inheritance"} 


@EndNode

@Node "Classes and methods" "beginner.guide/Classes and methods"
@Next "Example class"
@Toc "OOP Introduction"

Classes and methods
-------------------

   The heart of OOP is the `Black Box' approach to programming.  The kind
of black box in question is one where the contents are unknown but there
is a number of wires on the outside which give you some way of interacting
with the stuff on the inside.  The black boxes of OOP are actually
collections of data (just like the idea of variables that we've already
met) and they are called @{fg shine}objects@{fg text} (this is the general term, which is,
coincidentally, connected with the @{b}OBJECT@{ub} type in E).  Objects can be
grouped together in @{fg shine}classes@{fg text}, like the types for variables, except that a
class also defines what different kinds of wires protrude from the black
box.  This extra bit (the wires) is known as the @{fg shine}interface@{fg text} to the
object, and is made up of a number of @{fg shine}methods@{fg text} (so a method is analogous
to a wire).  Each method is actually just like a procedure.  With a real
black box, the wires are the only way of interacting with the box, so the
methods of an object ought to be the @{i}only@{ui} way of creating and using the
object.  Of course, the methods themselves normally need to know the
internal workings of the object, just like the way the wires are normally
connected to something inside the black box.

   There are two special kinds of methods: @{fg shine}constructors@{fg text} and
@{fg shine}destructors@{fg text}.  A @{fg shine}constructor@{fg text} is a method which is used to
initialise the data in an object, and a class may have several different
constructors (allowing for different kinds of initialisation) or it may
have none if no special initialisation is necessary.  Constructors are
normally used to allocate the resources (such as memory) that an object
needs.  The deallocation of such resources is done by the @{fg shine}destructor@{fg text}, of
which there is at most one for each class.

   Protecting the contents of an object in the `black box' way is known as
@{fg shine}data-hiding@{fg text} (the data in the object is visible only to its methods), and
only allowing the contents of an object to be manipulated via its
interface is known as @{fg shine}data abstraction@{fg text}.  By using this approach, only
the methods know the structure of the data in an object and so this
structure can be changed without affecting the whole of a program: only
the methods would potentially need recoding.  As you might be able to
tell, this simplifies maintenance quite considerably.


@EndNode

@Node "Example class" "beginner.guide/Example class"
@Next "Inheritance"
@Prev "Classes and methods"
@Toc "OOP Introduction"

Example class
-------------

   A good example of a class is the mathematical notion of a set (of
integers).  A particular object from this class would represent a
particular set of integers.  The interface for the class would probably
include the following methods:

  1.     @{b}Add@{ub} -- adds an integer to a set object.

  2.     @{b}Member@{ub} -- tests for membership of an integer in a set object.

  3.     @{b}Empty@{ub} -- tests for emptiness of a set object.

  4.     @{b}Union@{ub} --  unions a set object with a set object.

A more complete class would also contain methods for removing elements,
intersecting sets etc.  The important thing to notice is that to use this
class you need to know only how to use the methods.  The black box
approach means that we don't (and shouldn't) know how the set class is
actually implemented, i.e., how data is structured within a set object.
Only the methods themselves need to know how to manipulate the data that
represents a set object.

   The benefit of OOP comes when you actually use the classes, so suppose
you implement this set class and then use it in your code for some
database program.  If you found that the set implementation was a bit
inefficient (in terms of memory or speed), then, since you programmed in
this OOP way, you wouldn't have to recode the whole database program, just
the set class!  You can change the way the set data is structured in an
object as much and as often as you like, so long as each implementation
has the same interface (and gives the same results!).


@EndNode

@Node "Inheritance" "beginner.guide/Inheritance"
@Prev "Example class"
@Toc "OOP Introduction"

Inheritance
-----------

   The remaining OOP concept of interest is @{fg shine}inheritance@{fg text}.  This is a
grand name for a way of building on classes that enables the @{fg shine}derived@{fg text}
(i.e., bigger) class to be used as if its objects were really members of
the inherited, or @{fg shine}base@{fg text}, class.  For example, suppose class @{b}D@{ub} were
derived from class @{b}B@{ub}, so @{b}D@{ub} is the derived class and @{b}B@{ub} is the base class.
In this case, class @{b}D@{ub} inherits the data structure of class @{b}B@{ub}, and may add
extra data to it.  It also inherits all the methods of class @{b}B@{ub}, and
objects of class @{b}D@{ub} may be treated as if they were really objects of class
@{b}B@{ub}.

   Of course, an inherited method cannot affect the extra data in class @{b}D@{ub},
only the inherited data.  To affect the extra data, class @{b}D@{ub} can have extra
methods defined, or it can make new definitions for the inherited methods.  The
latter approach is only really useful if the new definition of an
inherited method is pretty similar to the inherited method, differing only
in how it affects the extra data in class @{b}D@{ub}.  This overriding of methods
does not affect the methods in class @{b}B@{ub} (nor those of other classes derived
from @{b}B@{ub}), but only those in class @{b}D@{ub} and the classes derived from @{b}D@{ub}.


@EndNode

@Node "Objects in E" "beginner.guide/Objects in E"
@Next "Methods in E"
@Prev "OOP Introduction"
@Toc "Object Oriented E"

Objects in E
============

   Classes are defined using @{b}OBJECT@{ub} in the same way that we've seen before
(see @{"OBJECT Type" Link "OBJECT Type"}).  So, in E, the terms `object declaration' and `class'
may be used interchangeably.  However, referring to an @{b}OBJECT@{ub} type as a
`class' signals the presence of methods in an object.

   The following example @{b}OBJECT@{ub} is the basis of a set class, as described
above (see @{"Example class" Link "Example class"}).  This set implementation is going to be quite
simple and it will be limited to a maximum of 100 elements.

     OBJECT set
       elts[100]:ARRAY OF LONG
       size
     ENDOBJECT

   Currently, the only way to allocate an OOP object is to use @{b}NEW@{ub} with an
appropriately typed pointer.  The following sections of code all allocate
memory for the data of @{b}set@{ub}, but only the last one allocates an OOP @{b}set@{ub}
object.  Each one may use and access the @{b}set@{ub} data, but only the last one
may call the methods of @{b}set@{ub}.

       DEF s:set
     
       DEF s:PTR TO set
       s:=NewR(SIZEOF set)
     
       DEF s:PTR TO set
       s:=NEW s

OOP objects can, of course, be deallocated using @{b}END@{ub}, in which case the
destructor for the corresponding class is also called.  Leaving an OOP
object to be deallocated automatically at the end of the program is not
quite as safe as normal, since in this case the destructor will not be
called.  Constructors and destructors are described in more detail below.


@EndNode

@Node "Methods in E" "beginner.guide/Methods in E"
@Next "Inheritance in E"
@Prev "Objects in E"
@Toc "Object Oriented E"

Methods in E
============

   The @{fg shine}methods@{fg text} of E are very similar to normal procedures, but there is
one, big difference: a method is part of a class, so must somehow be
identified with the other parts of the class.  In E this identification is
done by relating all methods to the corresponding @{b}OBJECT@{ub} type for the
class, using the @{b}OF@{ub} keyword after the description of the method's
parameters.  So, the methods of the simple set class would be defined as
outlined below (of course, these examples have omitted the code of
methods).

     PROC add(x) OF set
       /* code for add method */
     ENDPROC
     
     PROC member(x) OF set
       /* code for member method */
     ENDPROC
     
     PROC empty() OF set
       /* code for empty method */
     ENDPROC
     
     PROC union(s:PTR TO set) OF set
       /* code for union method */
     ENDPROC

   At first sight it might seem that the particular @{b}set@{ub} object which would
be manipulated by these methods is missing from the parameters.  For
instance, it appears that the @{b}empty@{ub} method should need an extra @{b}PTR TO set@{ub}
parameter, and that would be the @{b}set@{ub} object it tested for emptiness.
However, methods are called in a slightly different way to normal
procedures.  A method is a part of a class, and is called in a similar way
to accessing the data elements of the class.  That is, the method is
selected using @{b}.@{ub} and acts (implicitly) on the object from which it was
selected.  The following example shows the allocation of a set object and
the use of some of the above methods.

       DEF s:PTR TO set
       NEW s  -> Allocate an OOP object
       s.add(17)
       s.add(-34)
       IF s.empty()
         WriteF('Error: the set s should not be empty!\n')
       ELSE
         WriteF('OK: not empty\n')
       ENDIF
       IF s.member(0)
         WriteF('Error: how did 0 get in there?\n')
       ELSE
         WriteF('OK: 0 is not a member\n')
       ENDIF
       IF s.member(-34)
         WriteF('OK: -34 is a member\n')
       ELSE
         WriteF('Error: where has -34 gone?\n')
       ENDIF
       END s  -> Finished with s now

This is why the methods do not take that extra @{b}PTR TO set@{ub} argument.  If a
method is called then it has been selected from an appropriate object, and
so this must be the object which it affects.  The slightly complicated
method is @{b}union@{ub} which adds another @{b}set@{ub} object by unioning it.  In this
case, the argument to the method is a @{b}PTR TO set@{ub}, but this is the set to
be added, not the set which is being expanded.

   So, how do you refer to the object which is being affected?  In other
words, how do you affect it?  Well, this is the remaining difference from
normal procedures: every method has a special local variable, @{b}self@{ub}, which
is of type @{b}PTR TO @{ub}@{fg shine}class@{fg text}@{b}@{ub} and is initialised to point to the object from
which the method was selected.  Using this variable, the data and methods
of object can be accessed and used as normal.  For instance, the @{b}empty@{ub}
method has a @{b}self@{ub} local variable of type @{b}PTR TO set@{ub}, and can be defined as
below:

     PROC empty() OF set IS self.size=0

   @{fg shine}Constructors@{fg text} are simply methods which initialise the data of an
object.  For this reason they should normally be called only when the
object is allocated.  The @{b}NEW@{ub} operator allows OOP objects to call a
constructor at the point at which they are allocated, to make this easier
and more explicit.  The constructor will be called after @{b}NEW@{ub} has allocated
the memory for the object.  It is wise to give constructors suggestive
names like @{b}create@{ub} and @{b}copy@{ub}, or the same name as the class.  The following
constructors might be defined for the set class:

     /* Create empty set */
     PROC create() OF set
       self.size=0
     ENDPROC
     
     /* Copy existing set */
     PROC copy(oldset:PTR TO set) OF set
       DEF i
       FOR i:=0 TO oldset.size-1
         self.elements[i]:=oldset.elements[i]
       ENDFOR
       self.size:=oldset.size
     ENDPROC

They would be used as in the code below.  Notice that the @{b}create@{ub}
constructor is, in this case, redundant since @{b}NEW@{ub} will initialise the data
elements to zero.  If @{b}NEW@{ub} does sufficient initialisation then you do not
have to define any constructors, and even if you do have constructors you
don't @{i}have@{ui} to use them when allocating objects.

       DEF s:PTR TO set, t:PTR TO set, u:PTR TO set
       NEW s.create()
       IF s.empty THEN WriteF('s is empty\n')
       END s
       NEW t  /* This happens to be the same as using create */
       IF t.empty THEN WriteF('t is empty\n')
       t.add(10)
       NEW u.copy(t)
       IF u.member(10) THEN WriteF('10 is in u\n')
       END t, u

   For each class there is at most one @{fg shine}destructor@{fg text}, and this is
responsible for clearing up and deallocating resources.  If one is needed
then it must be called @{b}end@{ub}, and (as this might suggest) it is called
automatically when an OOP object is deallocated using @{b}END@{ub}.  So, for OOP
objects with a destructor, the (roughly) equivalent code to @{b}END@{ub} using
@{b}Dispose@{ub} is a bit different.  Take care to note that the destructor is @{i}not@{ui}
called if @{b}END@{ub} is not used to deallocate an OOP object (i.e., if
deallocation is left to be done automatically at the end of the program).

       END p
     
       IF p
         p.end()  -> Call destructor
         Dispose(p)
         p:=NIL
       ENDIF

   The simple implementation of the set class needs no destructor.  If,
however, the @{b}elements@{ub} data were a pointer (to @{b}LONG@{ub}), and the array were
allocated based on some size parameter to a constructor, then a destructor
would be useful.  In this case the set class would also need a @{b}maxsize@{ub}
data element, which records the maximum, allocated size of the @{b}elements@{ub}
array.

     OBJECT set
       elements:PTR TO LONG
       size
       maxsize
     ENDOBJECT
     
     PROC create(sz=100) OF set  -> Default to 100
       DEF p:PTR TO LONG
       self.maxsize:=IF (sz>0) AND (sz<100000) THEN sz ELSE 100
       self.elements:=NEW p[self.maxsize]
     ENDPROC
     
     PROC end() OF set
       DEF p:PTR TO LONG
       IF self.maxsize=0
         WriteF('Error: did not create() the set\n')
       ELSE
         p:=self.elements
         END p[self.maxsize]
       ENDIF
     ENDPROC

Without the destructor @{b}end@{ub}, the memory allocated for @{b}elements@{ub} would not be
deallocated when @{b}END@{ub} is used, although it would get deallocated at the end
of the program (in this case).  However, if @{b}AllocMem@{ub} were used instead of
@{b}NEW@{ub} to allocate the array, then the memory would have to be deallocated
using @{b}FreeMem@{ub}, and this would best be done in the destructor, as above.
(The memory would not be deallocated automatically at the end of the
program if @{b}AllocMem@{ub} is used.) Another solution to this kind of problem
would be to have a special method which called @{b}FreeMem@{ub}, and to remember to
call this method just before deallocating one of these objects, so you can
see that the interaction of @{b}END@{ub} with destructors is quite useful.

   Already, the above re-definition of @{b}set@{ub} begins to show the power of OOP.
The actual implementation of the set class is very different, but the
interface can remain the same.  The code for the methods would need to
change to take into account the new @{b}maxsize@{ub} element (where before the
fixed size of 100 was used), and also to deal with the possibility the
@{b}create@{ub} constructor had not been used (in which case @{b}elements@{ub} would be @{b}NIL@{ub}
and @{b}maxsize@{ub} zero).  But the code which used the set class would not need
to change, except maybe to allocate more sensibly sized sets!

   Yet another, different implementation of a set was outlined above (see
@{"Binary Trees" Link "Binary Trees"}).  In fact, remarkably few changes would be needed to convert
the code from that section into another implementation of the set class.
The @{b}new_set@{ub} procedure is like a set constructor which initialises the set
to be a singleton (i.e., to contain one element), and the @{b}add@{ub} procedure is
just like the @{b}add@{ub} method of the set class.  The only slight problem is
that empty sets are not modelled by the binary tree implementation, so it
wouldn't, as it stands, be a complete implementation.  It would be
straight-forward (but unduly complicated at this point) to add support for
empty sets to this particular implementation.


@EndNode

@Node "Inheritance in E" "beginner.guide/Inheritance in E"
@Next "Data-Hiding in E"
@Prev "Methods in E"
@Toc "Object Oriented E"

Inheritance in E
================

   One class is @{fg shine}derived@{fg text} from another using the @{b}OF@{ub} keyword in the
definition of the derived class @{b}OBJECT@{ub}, in a similar way that @{b}OF@{ub} is used
with methods.  For instance, the following code shows how to define the
class @{b}d@{ub} to be derived from class @{b}b@{ub}.  The class @{b}b@{ub} is then said to be
@{fg shine}inherited@{fg text} by the class @{b}d@{ub}.

     OBJECT b
       b_data
     ENDOBJECT
     
     OBJECT d OF b
       extra_d_data
     ENDOBJECT

The names @{b}b@{ub} and @{b}d@{ub} have been chosen to be somewhat suggestive, since the
class which is inherited (i.e., @{b}b@{ub}) is known as the @{fg shine}base@{fg text} class, whilst
the inheriting class (i.e., @{b}d@{ub}) is known as the @{fg shine}derived@{fg text} class.

   The definition of @{b}d@{ub} is the same as the following definition of @{b}duff@{ub},
except for one major difference: with the above derivation the methods of
@{b}b@{ub} are also inherited by @{b}d@{ub} and they become methods of class @{b}d@{ub}.  The
definition of @{b}duff@{ub} relates it in no way to @{b}b@{ub}, except at best accidentally
(since any changes to @{b}b@{ub} do not affect @{b}duff@{ub}, whereas they would affect @{b}d@{ub}).

     OBJECT duff
       b_data
       extra_d_data
     ENDOBJECT

   One property of this derivation applies to the data records built by
@{b}OBJECT@{ub} as well as the OOP classes.  The data records of type @{b}d@{ub} or @{b}duff@{ub} may
be used wherever a data record of type @{b}b@{ub} were required (e.g., the argument
to some procedure), and they are, in fact, indistinguishable from records
of type @{b}b@{ub}.  Although, if the definition of @{b}b@{ub} were changed (e.g., by
changing the name of the @{b}b_data@{ub} element) then data records of type @{b}duff@{ub}
would not be usable in this way, but those of type @{b}d@{ub} still would.
Therefore, it is wise to use inheritance to show the relationships between
classes or data of @{b}OBJECT@{ub} types.  The following example shows how
procedure @{b}print_b_data@{ub} can validly be called in several ways, given the
definitions of @{b}b@{ub}, @{b}d@{ub} and @{b}duff@{ub} above.

     PROC print_b_data(p:PTR TO b)
       WriteF('b_data = \d\n', p.b_data)
     ENDPROC
     
     PROC main()
       DEF p_b:PTR TO b, p_d:PTR TO d, p_duff:PTR TO duff
       NEW p_b, p_d, p_duff
       p_b.b_data:=11
       p_d.b_data:=-3
       p_duff.b_data:=27
       WriteF('Printing p_b: ')
       print_b_data(p_b)
       WriteF('Printing p_d: ')
       print_b_data(p_d)
       WriteF('Printing p_duff: ')
       print_b_data(p_duff)
     ENDPROC

   So far, no methods have been defined for @{b}b@{ub}, which means that it is just
an @{b}OBJECT@{ub} type.  The procedure @{b}print_b_data@{ub} suggests a useful method of @{b}b@{ub},
which will be called @{b}print@{ub}.

     PROC print() OF b
       WriteF('b_data = \d\n', self.b_data)
     ENDPROC

This definition would also define a @{b}print@{ub} method for @{b}d@{ub}, since @{b}d@{ub} is derived
from @{b}b@{ub} and it inherits all the methods of @{b}b@{ub}.  However, @{b}duff@{ub} would, of
course, still be just an @{b}OBJECT@{ub} type, although it could have a similar
@{b}print@{ub} method explicitly defined for it.  If @{b}b@{ub} has any methods defined for
it (i.e., if it is a class) then data records of type @{b}duff@{ub} cannot be used
as if they were @{i}objects@{ui} of the class @{b}b@{ub}, and it is not safe to try!  In
this case, only objects of derived class @{b}d@{ub} can be used in this manner.
(If @{b}b@{ub} is a class then @{b}d@{ub} is a class, due to inheritance.)

     PROC main()
       DEF p_b:PTR TO b, p_d:PTR TO d, p_duff:PTR TO duff
       NEW p_b, p_d, p_duff
       p_b.b_data:=11
       p_d.b_data:=-3;   p_d.extra_d_data:=3
       p_duff.b_data:=7; p_duff.extra_d_data:=-7
       WriteF('Printing p_b: ')
     /* b explicitly has print method  */
       p_b.print()
       WriteF('Printing p_d: ')
     /* d inherits print method from b */
       p_d.print()
       WriteF('No print method for p_duff\n')
     /* Do not try to print p_duff in this way */
     /*  p_duff.print() */
     ENDPROC

   Unfortunately, the @{b}print@{ub} method inherited by @{b}d@{ub} only prints the @{b}b_data@{ub}
element (since it is really a method of @{b}b@{ub}, so cannot access the extra data
added in @{b}d@{ub}).  However, any inherited method can be overridden by defining
it again, this time for the derived class.

     PROC print() OF d
       WriteF('extra_d_data = \d, ', self.extra_d_data)
       WriteF('b_data = \d\n', self.b_data)
     ENDPROC

With this extra definition, the same @{b}main@{ub} procedure above would now print
all the data of @{b}d@{ub}, but only the @{b}b_data@{ub} element of @{b}b@{ub}.  This is because the
new definition of @{b}print@{ub} affects only class @{b}d@{ub} (and classes derived from @{b}d@{ub}).

   Inherited methods are often overridden just to add extra functionality,
as in the case above where we wanted the extra data to be printed as well
as the data derived from @{b}b@{ub}.  For this purpose, the @{b}SUPER@{ub} operator can be
used on a method call to force the base class method to be used, where
normally the derived class method would be used.  So, the definition of
the @{b}print@{ub} method for class @{b}d@{ub} could call the @{b}print@{ub} method of class @{b}b@{ub}.

     PROC print() OF d
       WriteF('extra_d_data = \d, ', self.extra_d_data)
       SUPER self.print()
     ENDPROC

Be careful, though, because without the @{b}SUPER@{ub} operator this would involve
a recursive call to the @{b}print@{ub} method of class @{b}d@{ub}, rather than a call to the
base class method.

   Just as data records of type @{b}d@{ub} can be used wherever data records of
type @{b}b@{ub} were required, objects of class @{b}d@{ub} can used in place of objects of
class @{b}b@{ub}.  The following procedure prints a message and the object data,
using the @{b}print@{ub} method of @{b}b@{ub}.  (Of course, only the methods named by class
@{b}b@{ub} can be used in such a procedure, since the pointer @{b}p@{ub} is of type @{b}PTR
TO b@{ub}.)

     PROC msg_print(msg, p:PTR TO b)
       WriteF('Printing \s: ', msg)
       p.print()
     ENDPROC
     
     PROC main()
       DEF p_b:PTR TO b, p_d:PTR TO d
       NEW p_b, p_d
       p_b.b_data:=11
       p_d.b_data:=-3; p_d.extra_d_data:=3
       msg_print('p_b', p_b)
       msg_print('p_d', p_d)
     ENDPROC

You can't use @{b}duff@{ub} now, since it is not a class and @{b}b@{ub} is, and @{b}msg_print@{ub}
expects a pointer to class @{b}b@{ub}.  The only other objects that can be passed
to @{b}msg_print@{ub} are objects from classes derived from @{b}b@{ub}, and this is why @{b}p_d@{ub}
can be printed using @{b}msg_print@{ub}.  If you collect together the code and run
the example you will see that the call to @{b}print@{ub} in @{b}msg_print@{ub} uses the
overridden @{b}print@{ub} method when @{b}msg_print@{ub} is called with @{b}p_d@{ub} as a parameter.
That is, the correct method is called even though the pointer @{b}p@{ub} is not of
type @{b}PTR TO d@{ub}.  This is called @{fg shine}polymorphism@{fg text}: different implementations
of @{b}print@{ub} may be called depending on the real, @{fg shine}dynamic@{fg text} type of @{b}p@{ub}.  Here's
what should be printed:

     Printing p_b: b_data = 11
     Printing p_d: extra_d_data = 3, b_data = -3

   Inheritance is not limited to a single layer: you can derive other
classes from @{b}b@{ub}, you can derive classes from @{b}d@{ub}, and so on.  For instance,
if class @{b}e@{ub} is derived from class @{b}d@{ub} then it would inherit all the data of @{b}d@{ub}
and all the methods of @{b}d@{ub}.  This means that @{b}e@{ub} would inherit the richer
version of @{b}print@{ub}, and may even override it yet again.  In this case, class
@{b}e@{ub} would have two base classes, @{b}b@{ub} and @{b}d@{ub}, but would be derived directly from
@{b}d@{ub} (and indirectly from @{b}b@{ub}, via @{b}d@{ub}).  Class @{b}d@{ub} would therefore be known as the
@{fg shine}super@{fg text} class of @{b}e@{ub}, since @{b}e@{ub} is derived directly from @{b}d@{ub}.  (The super class
of @{b}d@{ub} is its only base class, @{b}b@{ub}.) So, the @{b}SUPER@{ub} operator is actually used
to call the methods in the super class.  In this example, the @{b}SUPER@{ub}
operator can be used in the methods of @{b}e@{ub} to call methods of @{b}d@{ub}.

   The binary tree implementation above (see @{"Binary Trees" Link "Binary Trees"}) suggests a good
example for a @{fg shine}class hierarchy@{fg text} (a collection of classes related by
inheritance).  A basic tree structure can be encapsulated in a base class
definition, and then specific kinds of tree (with different data at the
nodes) can be derived from this.  In fact, the base class @{b}tree@{ub} defined
below is only useful for inheriting, since a tree is pretty useless
without some data attached to the nodes.  Since it is very likely that
objects of class @{b}tree@{ub} will never be useful (but objects of classes derived
from @{b}tree@{ub} would be), the @{b}tree@{ub} class is called an @{fg shine}abstract@{fg text} class.

     OBJECT tree
       left:PTR TO tree, right:PTR TO tree
     ENDOBJECT
     
     PROC nodes() OF tree
       DEF tot=1
       IF self.left  THEN tot:=tot+self.left.nodes()
       IF self.right THEN tot:=tot+self.right.nodes()
     ENDPROC tot
     
     PROC leaves(show=FALSE) OF tree
       DEF tot=0
       IF self.left
         tot:=tot+self.left.leaves(show)
       ENDIF
       IF self.right
         tot:=tot+self.right.leaves(show)
       ELSEIF self.left=NIL
         IF show THEN self.print_node()
         tot++
       ENDIF
     ENDPROC tot
     
     PROC print_node() OF tree
       WriteF('<NULL> ')
     ENDPROC
     
     PROC print() OF tree
       IF self.left  THEN self.left.print()
       self.print_node()
       IF self.right THEN self.right.print()
     ENDPROC

The @{b}nodes@{ub} and @{b}leaves@{ub} methods return the number of nodes and leaves of the
tree, respectively, with the @{b}leaves@{ub} method taking a flag to specify
whether the leaves should also be printed.  These methods should never
need overriding in a class derived from @{b}tree@{ub}, and neither should @{b}print@{ub},
which traverses the tree, printing the nodes from left to right.  However,
the @{b}print_node@{ub} method probably should be overridden, as is the case in the
integer tree defined below.

     OBJECT integer_tree OF tree
       int
     ENDOBJECT
     
     PROC create(i) OF integer_tree
       self.int:=i
     ENDPROC
     
     PROC add(i) OF integer_tree
       DEF p:PTR TO integer_tree
       IF i < self.int
         IF self.left
           p:=self.left
           p.add(i)
         ELSE
           self.left:=NEW p.create(i)
         ENDIF
       ELSEIF i > self.int
         IF self.right
           p:=self.right
           p.add(i)
         ELSE
           self.right:=NEW p.create(i)
         ENDIF
       ENDIF
     ENDPROC
     
     PROC print_node() OF integer_tree
       WriteF('\d ', self.int)
     ENDPROC

   This is a nice example of polymorphism at work: we can implement a @{b}tree@{ub}
which works with integers simply by defining the appropriate methods.  The
@{b}leaves@{ub} method (of the @{b}tree@{ub} class) will then automatically call the
@{b}integer_tree@{ub} version of @{b}print_node@{ub} whenever we pass it an @{b}integer_tree@{ub}
object.  The definitions of @{b}tree@{ub} and @{b}integer_tree@{ub} can even be in different
modules (see @{"Data-Hiding in E" Link "Data-Hiding in E"}), and, using these OOP techniques, the
module containing @{b}tree@{ub} would not need to be recompiled even if a class
like @{b}integer_tree@{ub} is added or changed.  This shows why OOP is good for
code-reuse and extensibility: with traditional programming techniques we
would have to adapt the binary tree functions to account for integers, and
again for each new datatype.

   Notice that the recursive use of the new method @{b}add@{ub} must be called via
an auxiliary pointer, @{b}p@{ub}, of the derived class.  This is because the @{b}left@{ub}
and @{b}right@{ub} elements of @{b}tree@{ub} are pointers to @{b}tree@{ub} objects and @{b}add@{ub} is not a
method of @{b}tree@{ub} (the compiler would reject the code as a syntax error if
you tried to directly access @{b}add@{ub} under these circumstances).  Of course,
if the @{b}tree@{ub} class had an @{b}add@{ub} method there would not be this problem, but
what would the code be for such a method?

   An @{b}add@{ub} method does not really make sense for @{b}tree@{ub}, but if almost all
classes derived from @{b}tree@{ub} are going to need such a method it might be nice
to include it in the @{b}tree@{ub} base class.  This is the purpose of @{fg shine}abstract@{fg text}
methods.  An @{fg shine}abstract@{fg text} method is one which exists in a base class solely
so that it can be overridden in some derived class.  Normally, such
methods have no sensible definition in the base class, so there is a
special keyword, @{b}EMPTY@{ub}, which can be used to define them.  For example,
the @{b}add@{ub} method in @{b}tree@{ub} would be defined as below.

     PROC add(x) OF tree IS EMPTY

   With this definition, the code for the @{b}add@{ub} method for the @{b}integer_tree@{ub}
class could be simplified.  (The auxiliary pointer, @{b}p@{ub}, is still needed for
use with @{b}NEW@{ub}, since an expression like @{b}self.left@{ub} is not a pointer
variable.)

     PROC add(i) OF integer_tree
       DEF p:PTR TO integer_tree
       IF i < self.int
         IF self.left
           self.left.add(i)
         ELSE
           self.left:=NEW p.create(i)
         ENDIF
       ELSEIF i > self.int
         IF self.right
           self.right.add(i)
         ELSE
           self.right:=NEW p.create(i)
         ENDIF
       ENDIF
     ENDPROC

   This, however, is not the best example of an abstract method, since the
@{b}add@{ub} method in every class derived from @{b}tree@{ub} must now take a single @{b}LONG@{ub}
value as an parameter, in order to be compatible.  In general, though, a
class representing a tree with node data of type @{fg shine}t@{fg text} would really want an
@{b}add@{ub} method to take a single parameter of type @{fg shine}t@{fg text}.  The fact that a @{b}LONG@{ub}
value can represent a pointer to any type is helpful, here.  This means
that the definition of @{b}add@{ub} may not be so limiting, after all.

   The @{b}print_node@{ub} method is much more obviously suited to being an
abstract method.  The above definition prints something silly, because at
that point we didn't know about abstract methods and we needed the method
to be defined in the base class.  A much better definition would make
@{b}print_node@{ub} abstract.

     PROC print_node() OF tree IS EMPTY

It is quite safe to call these abstract methods, even for @{b}tree@{ub} class
objects.  If a method is still abstract in any class (i.e., it has not
been overridden), then calling it on objects of that class has the same
effect as calling a function which just returns zero (i.e., it does very
little!).

   The @{b}integer_tree@{ub} class could be used like this:

     PROC main()
       DEF t:PTR TO integer_tree
       NEW t.create(10)
       t.add(-10)
       t.add(3)
       t.add(5)
       t.add(-1)
       t.add(1)
       WriteF('t has \d nodes, with \d leaves: ',
              t.nodes(), t.leaves())
       t.leaves(TRUE)
       WriteF('\n')
       WriteF('Contents of t: ')
       t.print()
       WriteF('\n')
       END t
     ENDPROC


@EndNode

@Node "Data-Hiding in E" "beginner.guide/Data-Hiding in E"
@Prev "Inheritance in E"
@Toc "Object Oriented E"

Data-Hiding in E
================

   @{fg shine}Data-hiding@{fg text} is accomplished in E at the module level.  This means,
effectively, that it is wise to define classes in separate modules (or at
least only closely related classes together in a module), taking care to
@{b}EXPORT@{ub} only the definitions that you need to.  You can also use the
@{b}PRIVATE@{ub} keyword in the definition of any @{b}OBJECT@{ub} to hide all the
elements following it from code which uses the module (although this does
not affect the code within the module).  The @{b}PUBLIC@{ub} keyword can be used in
a similar way to make the elements which follow visible (i.e., accessible)
again, as they are by default.  For instance, the following @{b}OBJECT@{ub}
definition makes @{b}x@{ub}, @{b}y@{ub}, @{b}a@{ub} and @{b}b@{ub} private (so only visible to the code within
the same module), and @{b}p@{ub}, @{b}q@{ub} and @{b}r@{ub} public (so visible to code external to
the module, too).

     OBJECT rec
       p:INT
     PRIVATE
       x:INT
       y
     PUBLIC
       q
       r:PTR TO LONG
     PRIVATE
       a:PTR TO LONG, b
     ENDOBJECT

   For the set class you would probably want to make all the data private
and all the methods public.  In this way you force programs which use this
module to use the supplied interface, rather than fiddling with the set
data structures themselves.  The following example is the complete code
for a simple, inefficient set class, and can be compiled to a module.

     OPT MODULE  -> Define class 'set' in a module
     OPT EXPORT  -> Export everything
     
     /* The data for the class */
     OBJECT set PRIVATE  -> Make all the data private
       elements:PTR TO LONG
       maxsize, size
     ENDOBJECT
     
     /* Creation constructor */
     /* Minimum size of 1, maximum 100000, default 100 */
     PROC create(sz=100) OF set
       DEF p:PTR TO LONG
       self.maxsize:=IF (sz>0) AND (sz<100000) THEN sz ELSE 100 -> Check size
       self.elements:=NEW p[self.maxsize]
     ENDPROC
     
     /* Copy constructor */
     PROC copy(oldset:PTR TO set) OF set
       DEF i
       self.create(oldset.maxsize)  -> Call create method!
       FOR i:=0 TO oldset.size-1  -> Copy elements
         self.elements[i]:=oldset.elements[i]
       ENDFOR
       self.size:=oldset.size
     ENDPROC
     
     /* Destructor */
     PROC end() OF set
       DEF p:PTR TO LONG
       IF self.maxsize<>0  -> Check that it was allocated
         p:=self.elements
         END p[self.maxsize]
       ENDIF
     ENDPROC
     
     /* Add an element */
     PROC add(x) OF set
       IF self.member(x)=FALSE  -> Is it new? (Call member method!)
         IF self.size=self.maxsize
           Raise("full")  -> The set is already full
         ELSE
           self.elements[self.size]:=x
           self.size:=self.size+1
         ENDIF
       ENDIF
     ENDPROC
     
     /* Test for membership */
     PROC member(x) OF set
       DEF i
       FOR i:=0 TO self.size-1
         IF self.elements[i]=x THEN RETURN TRUE
       ENDFOR
     ENDPROC FALSE
     
     /* Test for emptiness */
     PROC empty() OF set IS self.size=0
     
     /* Union (add) another set */
     PROC union(other:PTR TO set) OF set
       DEF i
       FOR i:=0 TO other.size-1
         self.add(other.elements[i])  -> Call add method!
       ENDFOR
     ENDPROC
     
     /* Print out the contents */
     PROC print() OF set
       DEF i
       WriteF('{ ')
       FOR i:=0 TO self.size-1
         WriteF('\d ', self.elements[i])
       ENDFOR
       WriteF('}')
     ENDPROC

   This class can be used in another module or program, as below:

     MODULE '*set'
     
     PROC main() HANDLE
       DEF s=NIL:PTR TO set
       NEW s.create(20)
       s.add(1)
       s.add(-13)
       s.add(91)
       s.add(42)
       s.add(-76)
       IF s.member(1) THEN WriteF('1 is a member\n')
       IF s.member(11) THEN WriteF('11 is a member\n')
       WriteF('s = ')
       s.print()
       WriteF('\n')
     EXCEPT DO
       END s
       SELECT exception
       CASE "NEW"
         WriteF('Out of memory\n')
       CASE "full"
         WriteF('Set is full\n')
       ENDSELECT
     ENDPROC


@EndNode

@Node "Introduction to the Examples" "beginner.guide/Introduction to the Examples"
@Next "String Handling and I-O"
@Prev "Object Oriented E"
@Toc "Main"

Introduction to the Examples
****************************

   In this part we shall go through some slightly larger examples than
those in the previous parts.  However, none of them are too big, so they
should still be easy to understand.  The note-worthy parts of each example
are described, and you may even find the odd comment in the code.  Large,
complicated programs benefit hugely from the odd well-placed and
descriptive comment.  This fact can't be stressed enough.

   All the examples will run on a standard Amiga, except for the one which
uses @{b}ReadArgs@{ub} (an AmigaDOS 2.0 function).  It is really worth upgrading
your system to AmigaDOS 2.0 (or above) if you are still using previous
versions.  The @{b}ReadArgs@{ub} example can only hint at the power and
friendliness of the newer system functions.  If you are fortunate enough
to have an A4000 or an accelerated machine, then the timing example will
give better (i.e., quicker) results.

   Supplied with this Guide should be a directory of sources of most of
the examples.  Here's a complete catalogue:

@{b}simple.e@{ub} 
     The simple program from the introduction.  See @{"A Simple Program" Link "A Simple Program"}.

@{b}while.e@{ub} 
     The slightly complicated @{b}WHILE@{ub} loop.  See @{"WHILE loop" Link "WHILE loop"}.

@{b}address.e@{ub} 
     The program which prints the addresses of some variables.  See
     @{"Finding addresses (making pointers)" Link "Finding addresses (making pointers)"}.

@{b}static.e@{ub} 
     The static data problem.  See @{"Static data" Link "Static data"}.

@{b}static2.e@{ub} 
     The first solution to the static data problem.  See @{"Static data" Link "Static data"}.

@{b}except.e@{ub} 
     An exception handler example.  See @{"Raising an Exception" Link "Raising an Exception"}.

@{b}except2.e@{ub} 
     Another exception handler example.  See @{"Raising an Exception" Link "Raising an Exception"}.

@{b}static3.e@{ub} 
     The second solution to the static data problem, using @{b}NEW@{ub}.  See
     @{"List and typed list allocation" Link "List and typed list allocation"}.

@{b}float.e@{ub} 
     The floating-point example program.  See @{"Floating-Point Functions" Link "Floating-Point Functions"}.

@{b}bintree.e@{ub} 
     The binary tree example.  See @{"Binary Trees" Link "Binary Trees"}.

@{b}tree.e@{ub} 
     The @{b}tree@{ub} and @{b}integer_tree@{ub} classes, as a module.  See @{"Inheritance in E" Link "Inheritance in E"}.

@{b}tree-use.e@{ub} 
     A program to use the @{b}integer_tree@{ub} class.  See @{"Inheritance in E" Link "Inheritance in E"}.

@{b}set.e@{ub} 
     The simple, inefficient @{b}set@{ub} class, as a module.  See @{"Data-Hiding in E" Link "Data-Hiding in E"}.

@{b}set-use.e@{ub} 
     A program to use the @{b}set@{ub} class.  See @{"Data-Hiding in E" Link "Data-Hiding in E"}.

@{b}csv-estr.e@{ub} 
     The CSV reading program using E-strings.  See @{"String Handling and I-O" Link "String Handling and I-O"}.

@{b}csv-norm.e@{ub} 
     The CSV reading program using normal strings.  See
     @{"String Handling and I-O" Link "String Handling and I-O"}.

@{b}csv-buff.e@{ub} 
     The CSV reading program using normal strings and a large buffer.  See
     @{"String Handling and I-O" Link "String Handling and I-O"}.

@{b}csv.e@{ub} 
     The CSV reading program using normal strings, a large buffer, and an
     exception handler.  See @{"String Handling and I-O" Link "String Handling and I-O"}.

@{b}timing.e@{ub} 
     The timing example.  See @{"Timing Expressions" Link "Timing Expressions"}.

@{b}args.e@{ub} 
     The argument parsing example for any AmigaDOS.  See @{"Any AmigaDOS" Link "Any AmigaDOS"}.

@{b}args20.e@{ub} 
     The argument parsing example for any AmigaDOS 2.0 and above.  See
     @{"AmigaDOS 2.0 (and above)" Link "AmigaDOS 2.0 (and above)"}.

@{b}gadgets.e@{ub} 
     The gadgets example.  See @{"Gadgets" Link "Gadgets"}.

@{b}idcmp.e@{ub} 
     The IDCMP and gadgets example.  See @{"IDCMP Messages" Link "IDCMP Messages"}.

@{b}graphics.e@{ub} 
     The graphics example.  See @{"Graphics" Link "Graphics"}.

@{b}screens.e@{ub} 
     The screens example, without an exception handler.  See @{"Screens" Link "Screens"}.

@{b}screens2.e@{ub} 
     The screens example again, but this time with an exception handler.
     See @{"Screens" Link "Screens"}.

@{b}dragon.e@{ub} 
     The dragon curve recursion example.  See @{"Recursion Example" Link "Recursion Example"}.


@EndNode

@Node "String Handling and I-O" "beginner.guide/String Handling and I-O"
@Next "Timing Expressions"
@Prev "Introduction to the Examples"
@Toc "Main"

String Handling and I/O
***********************

   This chapter shows how to use normal strings and E-strings, and also
how to read data from a file.  The programs use a number of the string
functions and make effective (but different) use of memory where possible.
The key points to understand are:

   @{b}*@{ub} The difference between normal strings and E-strings.

   @{b}*@{ub} The two methods of reading data from a file (line-by-line or all at
     once).

   @{b}*@{ub} The necessary allocation of memory for E-strings.

   @{b}*@{ub} The unnecessary, but advisable, deallocation of the E-string memory
     once it is no longer needed.  The deallocation could be left to the
     automatic deallocation at the end of the program, but that would
     waste an increasing amount of memory whilst the program was running.
     If the input data was large then memory could easily be exhausted.

   @{b}*@{ub} The way in which sections of an E-string (or a normal string, for
     that matter) can easily be turned into normal strings.

   @{b}*@{ub} The way exception handlers can tidy up programs.

   The problem to solve is reading of a CSV (comma separated variables)
file, which is a standard format file for databases and spreadsheets.  The
format is very simple: each record is a line (i.e., terminated with a
line-feed) and each field in a record is separated by a comma.  To make
this example a lot simpler, we will forbid a field to contain a comma
(normally this would require the field to be quoted).  So, a typical input
file would look like this:

     Field1,Field2,Field3
     10,19,-3
     fred,barney,wilma
     ,,last
     first,,

In this example all records have three fields, as is well illustrated by
the first line (i.e., the first record).  The last two records may seem a
bit strange, but they just show how fields can be blank.  In the last
record all but the first field are blank, and in the previous record all
but the last are blank.

   So now we know the format of the file to be read.  To operate on a file
we must first open it using the @{b}Open@{ub} function (from the @{b}dos.library@{ub}), and
to read the lines from the file we will use the @{b}ReadStr@{ub} (built-in)
function.  There will be four versions of a program to read a CSV file:
two of which read data line-by-line and two which read all the file at
once.  Of the two which read line-by-line, one manipulates the read lines
as E-strings and the other uses normal strings.  The use of normal strings
is arguably more advanced than the use of E-strings, since cunning tricks
are employed to make effective use of memory.  However, the programs are
not meant to show that E-strings are better than normal strings (or vice
versa), rather they are meant to show how to use strings properly.

     /* A suitably large size for the record buffer */
     CONST BUFFERSIZE=512
     
     PROC main()
       DEF filehandle, status, buffer[BUFFERSIZE]:STRING, filename
       filename:='datafile'
       IF filehandle:=Open(filename, OLDFILE)
         REPEAT
           status:=ReadStr(filehandle, buffer)
           /* This is the way to check ReadStr() actually read something */
           IF buffer[] OR (status<>-1) THEN process_record(buffer)
         UNTIL status=-1
         /* If Open() succeeded then we must Close() the file */
         Close(filehandle)
       ELSE
         WriteF('Error: Failed to open "\s"\n', filename)
       ENDIF
     ENDPROC
     
     PROC process_record(line)
       DEF i=1, start=0, end, len, s
       /* Show the whole line being processed */
       WriteF('Processing record: "\s"\n', line)
       REPEAT
         /* Find the index of a comma after the start index */
         end:=InStr(line, ',', start)
         /* Length is end index minus start index */
         len:=(IF end<>-1 THEN end ELSE EstrLen(line))-start
         IF len>0
           /* Allocate an E-string of the correct length */
           IF s:=String(len)
             /* Copy the portion of the line to the E-string s */
             MidStr(s, line, start, len)
             /* At this point we could do something useful... */
             WriteF('\t\d) "\s"\n', i, s)
             /* We've finished with the E-string so deallocate it */
             DisposeLink(s)
           ELSE
             /* It's a non-fatal error if the String() call fails */
             WriteF('\t\d) Memory exhausted! (len=\d)\n', len)
           ENDIF
         ELSE
           WriteF('\t\d) Empty Field\n', i)
         ENDIF
         /* The new start is after the end we found */
         start:=end+1
         INC i
       /* Once a comma is not found we've finished */
       UNTIL end=-1
     ENDPROC

   There are a couple of points worth noting about this program:

   @{b}*@{ub} A large E-string, @{b}buffer@{ub}, is used to hold each line before it is
     processed.  If a record exceeds the size of this E-string then
     @{b}ReadStr@{ub} will only read a partial record, and the next @{b}ReadStr@{ub}
     will read some more this record.  However, the program considers each
     call to @{b}ReadStr@{ub} to read a whole record, so it will get the records
     slightly wrong in this case.  This is a limitation of the program and
     it should be documented so that users know to constrain themselves to
     datafiles without long lines.

   @{b}*@{ub} The file name is `hard-wired' to be @{b}datafile@{ub}.  A more flexible
     program would allow this to be passed as an argument (see
     @{"Argument Parsing" Link "Argument Parsing"}).

   @{b}*@{ub}     @{b}ReadStr@{ub} may return -1 to indicate an error (usually when the end
     of the file has been reached), but the E-string read so far may still
     be valid.  The check on the E-string and error value is the proper
     way of deciding whether @{b}ReadStr@{ub} actually read anything from the file.

   @{b}*@{ub} Look carefully at the manipulation of the string indexes @{b}start@{ub} and
     @{b}end@{ub}, and the calculation of the length of a portion of a string.

   @{b}*@{ub}     @{b}MidStr@{ub} is used to copy a field from a record, so an E-string must
     be used to hold the field.

   @{b}*@{ub} The E-string @{b}s@{ub} is only valid between the successful allocation by
     @{b}string@{ub} and the @{b}DisposeLink@{ub}.  It would be incorrect to try to, for
     instance, print it at any other point.  On the other hand, a more
     complicated program may want to store up all the data, and so it may
     be inappropriate to deallocate the E-string at this point.  In this
     case, the pointer to the E-string could be stored and it might be
     valid for the rest of the program.

   @{b}*@{ub} The allocation using @{b}String@{ub} is very closely followed by deallocation
     using @{b}DisposeLink@{ub}.  This suggests that a single E-string could be
     allocated and used repeatedly (like @{b}buffer@{ub} is), due to the simple
     nature of this example.

   To change this to use normal strings (in a very memory efficient way),
we need to alter only the @{b}process_record@{ub} procedure.  Some note-worthy
differences are:

   @{b}*@{ub} Small parts of the E-string @{b}buffer@{ub} are turned into normal strings by
     terminating them with @{b}NIL@{ub} when necessary.  This involves changing a
     comma that is found.

   @{b}*@{ub} No new memory is allocated, rather the @{b}buffer@{ub} memory is reused (as
     described above).  This is fine for this example, although if the
     fields were needed after a record had been processed they would need
     to be copied, since the contents of @{b}buffer@{ub} are changed by @{b}ReadStr@{ub}.

     PROC process_record(line)
       DEF i=1, start=0, end, s
       /* Show the whole line being processed */
       WriteF('Processing record: "\s"\n', line)
       REPEAT
         /* Find the index of a comma after the start index */
         end:=InStr(line, ',', start)
         /* If a comma was found then terminate with a NIL */
         IF end<>-1 THEN line[end]:=NIL
         /* Point to the start of the field */
         s:=line+start
         IF s[]
           /* At this point we could do something useful... */
           WriteF('\t\d) "\s"\n', i, s)
         ELSE
           WriteF('\t\d) Empty Field\n', i)
         ENDIF
         /* The new start is after the end we found */
         start:=end+1
         INC i
       /* Once a comma is not found we've finished */
       UNTIL end=-1
     ENDPROC

   The next two versions of the program are basically the same: they both
read the whole file into one large, dynamically allocated buffer and then
process the data.  The second of the two versions also uses exceptions to
make the program much more readable.  The differences from the above
version which uses normal strings are:

   @{b}*@{ub} The @{b}main@{ub} procedure calculates the length of the data in the file and
     then uses @{b}New@{ub} to dynamically allocate some memory to hold it.

   @{b}*@{ub} The read data is terminated with a @{b}NIL@{ub} so that it can safely be
     treated as a (very long) normal string.

   @{b}*@{ub} The @{b}process_buffer@{ub} procedure splits the read data up into lots of
     normal strings, one for each line of data.

     PROC main()
       DEF buffer, filehandle, len, filename
       filename:='datafile'
       /* Get the length of data in the file */
       IF 0<(len:=FileLength(filename))
         /* Allocate just enough room for the data + a terminating NIL */
         IF buffer:=New(len+1)
           IF filehandle:=Open(filename, OLDFILE)
             /* Read whole file, checking amount read */
             IF len=Read(filehandle, buffer, len)
               /* Terminate buffer with a NIL just in case... */
               buffer[len]:=NIL
               process_buffer(buffer, len)
             ELSE
               WriteF('Error: File reading error\n')
             ENDIF
             /* If Open() succeeded then we must Close() the file */
             Close(filehandle)
           ELSE
             WriteF('Error: Failed to open "\s"\n', filename)
           ENDIF
           /* Deallocate buffer (not really necessary in this example) */
           Dispose(buffer)
         ELSE
           WriteF('Error: Insufficient memory to load file\n')
         ENDIF
       ELSE
         WriteF('Error: "\s" is an empty file\n', filename)
       ENDIF
     ENDPROC
     
     /* buffer is like a normal string since it's NIL-terminated */
     PROC process_buffer(buffer, len)
       DEF start=0, end
       REPEAT
         /* Find the index of a linefeed after the start index */
         end:=InStr(buffer, '\n', start)
         /* If a linefeed was found then terminate with a NIL */
         IF end<>-1 THEN buffer[end]:=NIL
         process_record(buffer+start)
         start:=end+1
       /* We've finished if at the end or no more linefeeds */
       UNTIL (start>=len) OR (end=-1)
     ENDPROC
     
     PROC process_record(line)
       DEF i=1, start=0, end, s
       /* Show the whole line being processed */
       WriteF('Processing record: "\s"\n', line)
       REPEAT
         /* Find the index of a comma after the start index */
         end:=InStr(line, ',', start)
         /* If a comma was found then terminate with a NIL */
         IF end<>-1 THEN line[end]:=NIL
         /* Point to the start of the field */
         s:=line+start
         IF s[]
           /* At this point we could do something useful... */
           WriteF('\t\d) "\s"\n', i, s)
         ELSE
           WriteF('\t\d) Empty Field\n', i)
         ENDIF
         /* The new start is after the end we found */
         start:=end+1
         INC i
       /* Once a comma is not found we've finished */
       UNTIL end=-1
     ENDPROC

   The program is now quite messy, with many error cases in the @{b}main@{ub}
procedure.  We can very simply change this by using an exception handler
and a few automatic exceptions.

     /* Some constants for exceptions (ERR_NONE is zero: no error) */
     ENUM ERR_NONE, ERR_LEN, ERR_NEW, ERR_OPEN, ERR_READ
     
     /* Make some exceptions automatic */
     RAISE ERR_LEN  IF FileLength()<=0,
           ERR_NEW  IF New()=NIL,
           ERR_OPEN IF Open()=NIL
     
     PROC main() HANDLE
       /* Note the careful initialisation of buffer and filehandle */
       DEF buffer=NIL, filehandle=NIL, len, filename
       filename:='datafile'
       /* Get the length of data in the file */
       len:=FileLength(filename)
       /* Allocate just enough room for the data + a terminating NIL */
       buffer:=New(len+1)
       filehandle:=Open(filename, OLDFILE)
       /* Read whole file, checking amount read */
       IF len<>Read(filehandle, buffer, len) THEN Raise(ERR_READ)
       /* Terminate buffer with a NIL just in case... */
       buffer[len]:=NIL
       process_buffer(buffer, len)
     EXCEPT DO
       /* Both of these are safe thanks to the initialisations */
       IF buffer THEN Dispose(buffer)
       IF filehandle THEN Close(filehandle)
       /* Report error (if there was one) */
       SELECT exception
       CASE ERR_LEN;   WriteF('Error: "\s" is an empty file\n', filename)
       CASE ERR_NEW;   WriteF('Error: Insufficient memory to load file\n')
       CASE ERR_OPEN;  WriteF('Error: Failed to open "\s"\n', filename)
       CASE ERR_READ;  WriteF('Error: File reading error\n')
       ENDSELECT
     ENDPROC

The code is now much clearer, and the majority of errors can be caught
automatically.  Notice that the exception handler is called even if the
program succeeds (thanks to the @{b}DO@{ub} after the @{b}EXCEPT@{ub}).  This is because
when the program terminates it needs to deallocate the resources it
allocated in every case (successful or otherwise), so the code is the same.
Conditional deallocation (of the buffer, for example) is made safe by an
appropriate initialisation.

   If you feel like a small exercise, try to write a similar program but
this time using the @{b}tools/file@{ub} module which comes in the standard Amiga E
distribution.  Of course, you'll first need to read the accompanying
documentation, but you should find that this module makes file interaction
very simple.


@EndNode

@Node "Timing Expressions" "beginner.guide/Timing Expressions"
@Next "Argument Parsing"
@Prev "String Handling and I-O"
@Toc "Main"

Timing Expressions
******************

   You may recall the outline of a timing procedure in Part Two (see
@{"Evaluation" Link "Evaluation"}).  This chapter gives the complete version of this example.
The information missing from the outline was how to determine the system
time and use this to calculate the time taken by calls to @{b}Eval@{ub}.  So the
things to notice about this example are:

   @{b}*@{ub} Use of the Amiga system function @{b}DateStamp@{ub} (from the @{b}dos.library@{ub}).
     (You really need the `Rom Kernel Reference Manuals' and the `AmigaDOS
     Manual' to understand the system functions.)

   @{b}*@{ub} Use of the module @{b}dos/dos@{ub} to include the definitions of the object
     @{b}datestamp@{ub} and the constant @{b}TICKS_PER_SECOND@{ub}.  (There are fifty ticks
     per second.)

   @{b}*@{ub} Use of the @{b}repeat@{ub} procedure to do @{b}Eval@{ub} a decent number of times for
     each expression (so that some time is taken up by the calls!).

   @{b}*@{ub} The timing of the evaluation of 0, to calculate the overhead of the
     procedure calls and loop.  This value is stored in the variable
     @{b}offset@{ub} the first time the @{b}test@{ub} procedure is called.  The
     expression 0 should take a negligible amount of time, so the number
     of ticks timed is actually the time taken by the procedure calls and
     loop calculations.  Subtracting this time from the other times gives
     a fair view of how long the expressions take, relative to one another.
     (Thanks to Wouter for this offset idea.)

   @{b}*@{ub} Use of @{b}Forbid@{ub} and @{b}Permit@{ub} to turn off multi-tasking temporarily,
     making the CPU calculate only the expressions (rather than dealing
     with screen output, other programs, etc.).

   @{b}*@{ub} Use of @{b}CtrlC@{ub} and @{b}CleanUp@{ub} to allow the user to stop the program if it
     gets too boring...

   @{b}*@{ub} Use of the option @{b}LARGE@{ub} (using @{b}OPT@{ub}) to produce an executable that
     uses the large data and code model.  This seems to help make the
     timings less susceptible variations due to, for instance,
     optimisations, and so better for comparison.  See the `Reference
     Manual' for more details.

   Also supplied are some example outputs.  The first was from an A1200
with 2MB Chip RAM and 4MB Fast RAM.  The second was from an A500Plus with
2MB Chip RAM.  Both used the constant @{b}LOTS_OF_TIMES@{ub} as 500,000, but you
might need to increase this number to compare, for instance, an A4000/040
to an A4000/030.  However, 500,000 gives a pretty long wait for results on
the A500.

     MODULE 'dos/dos'
     
     CONST TICKS_PER_MINUTE=TICKS_PER_SECOND*60, LOTS_OF_TIMES=500000
     
     DEF x, y, offset
     
     PROC fred(n)
       DEF i
       i:=n+x
     ENDPROC
     
     /* Repeat evaluation of an expression */
     PROC repeat(exp)
       DEF i
       FOR i:=0 TO LOTS_OF_TIMES
         Eval(exp)  /* Evaluate the expression */
       ENDFOR
     ENDPROC
     
     /* Time an expression, and set-up offset if not done already */
     PROC test(exp, message)
       DEF t
       IF offset=0 THEN offset:=time(`0)  /* Calculate offset */
       t:=time(exp)
       WriteF('\s:\t\d ticks\n', message, t-offset)
     ENDPROC
     
     /* Time the repeated calls, and calculate number of ticks */
     PROC time(x)
       DEF ds1:datestamp, ds2:datestamp
       Forbid()
       DateStamp(ds1)
       repeat(x)
       DateStamp(ds2)
       Permit()
       IF CtrlC() THEN CleanUp(1)
     ENDPROC ((ds2.minute-ds1.minute)*TICKS_PER_MINUTE)+ds2.tick-ds1.tick
     
     PROC main()
       x:=9999
       y:=1717
       test(`x+y,     'Addition')
       test(`y-x,     'Subtraction')
       test(`x*y,     'Multiplication')
       test(`x/y,     'Division')
       test(`x OR y,  'Bitwise OR')
       test(`x AND y, 'Bitwise AND')
       test(`x=y,     'Equality')
       test(`x<y,     'Less than')
       test(`x<=y,    'Less than or equal')
       test(`y:=1,    'Assignment of 1')
       test(`y:=x,    'Assignment of x')
       test(`y++,     'Increment')
       test(`IF FALSE THEN y ELSE x, 'IF FALSE')
       test(`IF TRUE THEN y ELSE x,  'IF TRUE')
       test(`IF x THEN y ELSE x,     'IF x')
       test(`fred(2),  'fred(2)')
     ENDPROC

Here's the output from the A1200:

     Addition:	22 ticks
     Subtraction:	22 ticks
     Multiplication:	69 ticks
     Division:	123 ticks
     Bitwise OR:	33 ticks
     Bitwise AND:	27 ticks
     Equality:	44 ticks
     Less than:	43 ticks
     Less than or equal:	70 ticks
     Assignment of 1:	9 ticks
     Assignment of x:	38 ticks
     Increment:	23 ticks
     IF FALSE:	27 ticks
     IF TRUE:	38 ticks
     IF x:	44 ticks
     fred(2):	121 ticks

Compare this to the output from the A500Plus:

     Addition:	118 ticks
     Subtraction:	117 ticks
     Multiplication:	297 ticks
     Division:	643 ticks
     Bitwise OR:	118 ticks
     Bitwise AND:	117 ticks
     Equality:	164 ticks
     Less than:	164 ticks
     Less than or equal:	164 ticks
     Assignment of 1:	60 ticks
     Assignment of x:	102 ticks
     Increment:	134 ticks
     IF FALSE:	118 ticks
     IF TRUE:	164 ticks
     IF x:	193 ticks
     fred(2):	523 ticks

Evidence, if it were needed, that the A1200 is roughly five times faster
than an A500, and that's not using the special 68020 CPU instructions!


@EndNode

@Node "Argument Parsing" "beginner.guide/Argument Parsing"
@Next "Gadgets IDCMP and Graphics"
@Prev "Timing Expressions"
@Toc "Main"

Argument Parsing
****************

   There are two examples in this chapter.  One is for any AmigaDOS and
the other is for AmigaDOS 2.0 and above.  They both illustrate how to
parse the arguments to your program.  If your program is started from the
Shell/CLI the arguments follow the command name on the command line, but
if it was started from Workbench (i.e., you double-clicked on an icon for
the program) then the arguments are those icons that were also selected at
that time (see your Workbench manual for more details).


 @{" Any AmigaDOS " Link "Any AmigaDOS"} 
 @{" AmigaDOS 2.0 (and above) " Link "AmigaDOS 2.0 (and above)"} 


@EndNode

@Node "Any AmigaDOS" "beginner.guide/Any AmigaDOS"
@Next "AmigaDOS 2.0 (and above)"
@Toc "Argument Parsing"

Any AmigaDOS
============

   This first example works with any AmigaDOS.  The first thing that is
done is the assignment of @{b}wbmessage@{ub} to a correctly typed pointer.  At the
same time we can check to see if it is @{b}NIL@{ub} (i.e., whether the program was
started from Workbench or not).  If it was not started from Workbench the
arguments in @{b}arg@{ub} are printed.  Otherwise we need to use the fact that
@{b}wbmessage@{ub} is really a pointer to a @{b}wbstartup@{ub} object (defined in module
@{b}workbench/startup@{ub}), so we can get at the argument list.  Then for each
argument in the list we need to check the lock supplied with the argument.
If it's a proper lock it will be a lock on the directory containing the
argument file.  The name in the argument is just a filename, not a
complete path, so to read the file we need to change the current directory
to the lock directory.  Once we've got a valid lock and we've changed
directory to there, we can find the length of the file (using @{b}FileLength@{ub})
and print it.  If there was no lock or the file did not exist, the name of
the file and an appropriate error message is printed.

     MODULE 'workbench/startup'
     
     PROC main()
       DEF startup:PTR TO wbstartup, args:PTR TO wbarg, i, oldlock, len
       IF (startup:=wbmessage)=NIL
         WriteF('Started from Shell/CLI\n   Arguments: "\s"\n', arg)
       ELSE
         WriteF('Started from Workbench\n')
         args:=startup.arglist
         FOR i:=1 TO startup.numargs  /* Loop through the arguments */
           IF args[].lock=NIL
             WriteF('  Argument \d: "\s" (no lock)\n', i, args[].name)
           ELSE
             oldlock:=CurrentDir(args[].lock)
             len:=FileLength(args[].name)  /* Do something with file */
             IF len=-1
               WriteF('  Argument \d: "\s" (file does not exist)\n',
                      i, args[].name)
             ELSE
               WriteF('  Argument \d: "\s", file length is \d bytes\n',
                      i, args[].name, len)
             ENDIF
             CurrentDir(oldlock) /* Important: restore current dir */
           ENDIF
           args++
         ENDFOR
       ENDIF
     ENDPROC

When you run this program you'll notice a slight difference between @{b}arg@{ub}
and the Workbench message: @{b}arg@{ub} does not contain the program name, just the
arguments, whereas the first argument in the Workbench argument list is
the program.  You can simply ignore the first Workbench argument in the
list if you want.


@EndNode

@Node "AmigaDOS 2.0 (and above)" "beginner.guide/AmigaDOS 2.0 (and above)"
@Prev "Any AmigaDOS"
@Toc "Argument Parsing"

AmigaDOS 2.0 (and above)
========================

   This second program can be used as the Shell/CLI part of the previous
program to provide much better command line parsing.  It can only be used
with AmigaDOS 2.0 and above (i.e., @{b}OSVERSION@{ub} which is 37 or more).  The
template @{b}FILE/M@{ub} used with @{b}ReadArgs@{ub} gives command line parsing similar to
C's @{b}argv@{ub} array.  The template can be much more interesting than this, but
for more details you need the `AmigaDOS Manual'.

     OPT OSVERSION=37
     
     PROC main()
       DEF templ, rdargs, args=NIL:PTR TO LONG, i
       IF wbmessage=NIL
         WriteF('Started from Shell/CLI\n')
         templ:='FILE/M'
         rdargs:=ReadArgs(templ,{args},NIL)
         IF rdargs
           IF args
             i:=0
             WHILE args[i]  /* Loop through arguments */
               WriteF('   Argument \d: "\s"\n', i, args[i])
               i++
             ENDWHILE
           ENDIF
           FreeArgs(rdargs)
         ENDIF
       ENDIF
     ENDPROC

As you can see the result of the @{b}ReadArgs@{ub} call with this template is an
array of filenames.  The special quoting of filenames is dealt with
correctly (i.e., when you use " around a filename that contains spaces).
You need to do all this kind of work yourself if you use the @{b}arg@{ub} method.


@EndNode

@Node "Gadgets IDCMP and Graphics" "beginner.guide/Gadgets IDCMP and Graphics"
@Next "Recursion Example"
@Prev "Argument Parsing"
@Toc "Main"

Gadgets, IDCMP and Graphics
***************************

   There are three examples in this chapter.  The first shows how to open
a window and put some gadgets on it.  The second shows how to decipher
Intuition messages that arrive via IDCMP.  The third draws things with the
graphics functions.


 @{" Gadgets " Link "Gadgets"} 
 @{" IDCMP Messages " Link "IDCMP Messages"} 
 @{" Graphics " Link "Graphics"} 
 @{" Screens " Link "Screens"} 


@EndNode

@Node "Gadgets" "beginner.guide/Gadgets"
@Next "IDCMP Messages"
@Toc "Gadgets IDCMP and Graphics"

Gadgets
=======

   The following program illustrates how to create a gadget list and use
it:

     MODULE 'intuition/intuition'
     
     CONST GADGETBUFSIZE = 4 * GADGETSIZE
     
     PROC main()
       DEF buf[GADGETBUFSIZE]:ARRAY, next, wptr
       next:=Gadget(buf,  NIL, 1, 0, 10, 30, 50, 'Hello')
       next:=Gadget(next, buf, 2, 3, 70, 30, 50, 'World')
       next:=Gadget(next, buf, 3, 1, 10, 50, 50, 'from')
       next:=Gadget(next, buf, 4, 0, 70, 50, 70, 'gadgets')
       wptr:=OpenW(20,50,200,100, 0, WFLG_ACTIVATE,
                   'Gadgets in a window',NIL,1,buf)
       IF wptr         /* Check to see we opened a window */
         Delay(500)    /* Wait a bit */
         CloseW(wptr)  /* Close the window */
       ELSE
         WriteF('Error -- could not open window!')
       ENDIF
     ENDPROC

Four gadgets are created using an appropriately sized array as the buffer.
These gadgets are passed to @{b}OpenW@{ub} (the last parameter).  If the window
could be opened a small delay is used so that the window is visible before
the program closes it and terminates.  @{b}Delay@{ub} is an Amiga system function
from the DOS library, and @{b}Delay(n)@{ub} waits n/50 seconds.  Therefore, the
window stays up for 10 seconds, which is enough time to play with the
gadgets and see what the different types are.  The next example will show
a better way of deciding when to terminate the program (using the standard
close gadget).


@EndNode

@Node "IDCMP Messages" "beginner.guide/IDCMP Messages"
@Next "Graphics"
@Prev "Gadgets"
@Toc "Gadgets IDCMP and Graphics"

IDCMP Messages
==============

   This next program shows how to use @{b}WaitIMessage@{ub} with a gadget.

     MODULE 'intuition/intuition'
     
     CONST GADGETBUFSIZE = GADGETSIZE, OURGADGET = 1
     
     PROC main()
       DEF buf[GADGETBUFSIZE]:ARRAY, wptr, class, gad:PTR TO gadget
       Gadget(buf, NIL, OURGADGET, 1, 10, 30, 100, 'Press Me')
       wptr:=OpenW(20,50,200,100,
                   IDCMP_CLOSEWINDOW OR IDCMP_GADGETUP,
                   WFLG_CLOSEGADGET OR WFLG_ACTIVATE,
                   'Gadget message window',NIL,1,buf)
       IF wptr              /* Check to see we opened a window */
         WHILE (class:=WaitIMessage(wptr))<>IDCMP_CLOSEWINDOW
           gad:=MsgIaddr()  /* Our gadget clicked? */
           IF (class=IDCMP_GADGETUP) AND (gad.userdata=OURGADGET)
             TextF(10,60,
                   IF gad.flags=0 THEN 'Gadget off ' ELSE 'Gadget on   ')
           ENDIF
         ENDWHILE
         CloseW(wptr)       /* Close the window */
       ELSE
         WriteF('Error -- could not open window!')
       ENDIF
     ENDPROC

The gadget reports its state when you click on it, using the @{b}TextF@{ub}
function (see @{"Graphics functions" Link "Graphics functions"}).  The only way to quit the program is
using the close gadget of the window.  The @{b}gadget@{ub} object is defined in the
module @{b}intuition/intuition@{ub} and the @{b}iaddr@{ub} part of the IDCMP message is a
pointer to our gadget if the message was a gadget message.  The @{b}userdata@{ub}
element of the gadget identifies the gadget that was clicked, and the
@{b}flags@{ub} element is zero if the boolean gadget is off (unselected) or
non-zero if the boolean gadget is on (selected).


@EndNode

@Node "Graphics" "beginner.guide/Graphics"
@Next "Screens"
@Prev "IDCMP Messages"
@Toc "Gadgets IDCMP and Graphics"

Graphics
========

   The following program illustrates how to use the various graphics
functions.

     MODULE 'intuition/intuition'
     
     PROC main()
       DEF wptr, i
       wptr:=OpenW(20,50,200,100,IDCMP_CLOSEWINDOW,
                   WFLG_CLOSEGADGET OR WFLG_ACTIVATE,
                   'Graphics demo window',NIL,1,NIL)
       IF wptr  /* Check to see we opened a window */
         Colour(1,3)
         TextF(20,30,'Hello World')
         SetTopaz(11)
         TextF(20,60,'Hello World')
         FOR i:=10 TO 150 STEP 8  /* Plot a few points */
           Plot(i,40,2)
         ENDFOR
         Line(160,40,160,70,3)
         Line(160,70,170,40,2)
         Box(10,75,160,85,1)
         WHILE WaitIMessage(wptr)<>IDCMP_CLOSEWINDOW
         ENDWHILE
         CloseW(wptr)
       ELSE
         WriteF('Error -- could not open window!\n')
       ENDIF
     ENDPROC

First of all a small window is opened with a close gadget and activated
(so it is the selected window).  Clicks on the close gadget will be
reported via IDCMP, and this is the only way to quit the program.  The
graphics functions are used as follows:

   @{b}*@{ub}     @{b}Colour@{ub} is used to set the foreground colour to pen one and the
     background colour to pen three.  This will make the text nicely
     highlighted.

   @{b}*@{ub} Text is output in the standard font.

   @{b}*@{ub} The font is set to Topaz 11.

   @{b}*@{ub} More text is output (probably now in a different font).

   @{b}*@{ub} The @{b}FOR@{ub} loop plots a dotted line in pen two.

   @{b}*@{ub} A vertical line in pen three is drawn.

   @{b}*@{ub} A diagonal line in pen two is drawn.  This and the previous line
     together produce a vee shape.

   @{b}*@{ub} A filled box is drawn in pen one.


@EndNode

@Node "Screens" "beginner.guide/Screens"
@Prev "Graphics"
@Toc "Gadgets IDCMP and Graphics"

Screens
=======

   This next example uses parts of the previous example, but also opens a
custom screen.  Basically, it draws coloured lines and boxes in a big
window opened on a 16 colour, high resolution screen.

     MODULE 'intuition/intuition', 'graphics/view'
     
     PROC main()
       DEF sptr=NIL, wptr=NIL, i
       sptr:=OpenS(640,200,4,V_HIRES,'Screen demo')
       IF sptr
         wptr:=OpenW(0,20,640,180,IDCMP_CLOSEWINDOW,
                     WFLG_CLOSEGADGET OR WFLG_ACTIVATE,
                     'Graphics demo window',sptr,$F,NIL)
         IF wptr
           TextF(20,20,'Hello World')
           FOR i:=0 TO 15  /* Draw a line and box in each colour */
             Line(20,30,620,30+(7*i),i)
             Box(10+(40*i),140,30+(40*i),170,1)
             Box(11+(40*i),141,29+(40*i),169,i)
           ENDFOR
           WHILE WaitIMessage(wptr)<>IDCMP_CLOSEWINDOW
           ENDWHILE
           WriteF('Program finished successfully\n')
         ELSE
           WriteF('Could not open window\n')
         ENDIF
       ELSE
         WriteF('Could not open screen\n')
       ENDIF
       IF wptr THEN CloseW(wptr)
       IF sptr THEN CloseS(sptr)
     ENDPROC

As you can see, the error-checking @{b}IF@{ub} blocks can make the program hard to
read.  Here's the same example written with an exception handler:

     MODULE 'intuition/intuition', 'graphics/view'
     
     ENUM WIN=1, SCRN
     
     RAISE WIN  IF OpenW()=NIL,
           SCRN IF OpenS()=NIL
     
     PROC main() HANDLE
       DEF sptr=NIL, wptr=NIL, i
       sptr:=OpenS(640,200,4,V_HIRES,'Screen demo')
       wptr:=OpenW(0,20,640,180,IDCMP_CLOSEWINDOW,
                   WFLG_CLOSEGADGET OR WFLG_ACTIVATE,
                   'Graphics demo window',sptr,$F,NIL)
       TextF(20,20,'Hello World')
       FOR i:=0 TO 15  /* Draw a line and box in each colour */
         Line(20,30,620,30+(7*i),i)
         Box(10+(40*i),140,30+(40*i),170,1)
         Box(11+(40*i),141,29+(40*i),169,i)
       ENDFOR
       WHILE WaitIMessage(wptr)<>IDCMP_CLOSEWINDOW
       ENDWHILE
     EXCEPT DO
       IF wptr THEN CloseW(wptr)
       IF sptr THEN CloseS(sptr)
       SELECT exception
       CASE 0
         WriteF('Program finished successfully\n')
       CASE WIN
         WriteF('Could not open window\n')
       CASE SCRN
         WriteF('Could not open screen\n')
       ENDSELECT
     ENDPROC

It's much easier to see what's going on here.  The real part of the
program (the bit before the @{b}EXCEPT@{ub}) is no longer cluttered with error
checking, and it's easy to see what happens if an error occurs.  Notice
that if the program successfully finishes it still has to close the screen
and window properly, so it's often sensible to use @{b}EXCEPT DO@{ub} to raise a
zero exception and deal with all the tidying up in the handler.


@EndNode

@Node "Recursion Example" "beginner.guide/Recursion Example"
@Next "Common Problems"
@Prev "Gadgets IDCMP and Graphics"
@Toc "Main"

Recursion Example
*****************

   This next example uses a pair of mutually recursive procedures to draw
what is known as a dragon curve (a pretty, space-filling pattern).

     MODULE 'intuition/intuition', 'graphics/view'
     
     /* Screen size, use SIZEY=512 for a PAL screen */
     CONST SIZEX=640, SIZEY=400
     
     /* Exception values */
     ENUM WIN=1, SCRN, STK, BRK
     
     /* Directions (DIRECTIONS gives number of directions) */
     ENUM NORTH, EAST, SOUTH, WEST, DIRECTIONS
     
     RAISE WIN  IF OpenW()=NIL,
           SCRN IF OpenS()=NIL
     
     /* Start off pointing WEST */
     DEF state=WEST, x, y, t
     
     /* Face left */
     PROC left()
       state:=Mod(state-1+DIRECTIONS, DIRECTIONS)
     ENDPROC
     
     /* Move right, changing the state */
     PROC right()
       state:=Mod(state+1, DIRECTIONS)
     ENDPROC
     
     /* Move in the direction we're facing */
     PROC move()
       SELECT state
       CASE NORTH; draw(0,t)
       CASE EAST;  draw(t,0)
       CASE SOUTH; draw(0,-t)
       CASE WEST;  draw(-t,0)
       ENDSELECT
     ENDPROC
     
     /* Draw and move to specified relative position */
     PROC draw(dx, dy)
       /* Check the line will be drawn within the window bounds */
       IF (x>=Abs(dx)) AND (x<=SIZEX-Abs(dx)) AND
          (y>=Abs(dy)) AND (y<=SIZEY-10-Abs(dy))
         Line(x, y, x+dx, y+dy, 2)
       ENDIF
       x:=x+dx
       y:=y+dy
     ENDPROC
     
     PROC main() HANDLE
       DEF sptr=NIL, wptr=NIL, i, m
       /* Read arguments:        [m [t [x  [y]]]] */
       /* so you can say: dragon  16              */
       /*             or: dragon  16 1            */
       /*             or: dragon  16 1 450        */
       /*             or: dragon  16 1 450 100    */
       /* m is depth of dragon, t is length of lines */
       /* (x,y) is the start position */
       m:=Val(arg, {i})
       t:=Val(arg:=arg+i, {i})
       x:=Val(arg:=arg+i, {i})
       y:=Val(arg:=arg+i, {i})
       /* If m or t is zero use a more sensible default */
       IF m=0 THEN m:=5
       IF t=0 THEN t:=5
       sptr:=OpenS(SIZEX,SIZEY,4,V_HIRES OR V_LACE,'Dragon Curve Screen')
       wptr:=OpenW(0,10,SIZEX,SIZEY-10,
                   IDCMP_CLOSEWINDOW,WFLG_CLOSEGADGET,
                   'Dragon Curve Window',sptr,$F,NIL)
       /* Draw the dragon curve */
       dragon(m)
       WHILE WaitIMessage(wptr)<>IDCMP_CLOSEWINDOW
       ENDWHILE
     EXCEPT DO
       IF wptr THEN CloseW(wptr)
       IF sptr THEN CloseS(sptr)
       SELECT exception
       CASE 0
         WriteF('Program finished successfully\n')
       CASE WIN
         WriteF('Could not open window\n')
       CASE SCRN
         WriteF('Could not open screen\n')
       CASE STK
         WriteF('Ran out of stack in recursion\n')
       CASE BRK
         WriteF('User aborted\n')
       ENDSELECT
     ENDPROC
     
     /* Draw the dragon curve (with left) */
     PROC dragon(m)
       /* Check stack and ctrl-C before recursing */
       IF FreeStack()<1000 THEN Raise(STK)
       IF CtrlC() THEN Raise(BRK)
       IF m>0
         dragon(m-1)
         left()
         nogard(m-1)
       ELSE
         move()
       ENDIF
     ENDPROC
     
     /* Draw the dragon curve (with right) */
     PROC nogard(m)
       IF m>0
         dragon(m-1)
         right()
         nogard(m-1)
       ELSE
         move()
       ENDIF
     ENDPROC

   If you write this to the file @{b}dragon.e@{ub} and compile it to the executable
@{b}dragon@{ub} then some good things to try are:

     dragon 5 9 300 100
     dragon 10 4 250 250
     dragon 11 3 250 250
     dragon 15 1 300 100
     dragon 16 1 400 150

   If you want to understand how the program works you need to study the
recursive parts.  Here's an overview of the program, outlining the
important aspects:

   @{b}*@{ub} The constants @{b}SIZEX@{ub} and @{b}SIZEY@{ub} are the width and height (respectively)
     of the custom screen (and window).  As the comment suggests, change
     @{b}SIZEY@{ub} to 512 if you want a bigger screen and you have a PAL Amiga.

   @{b}*@{ub} The @{b}state@{ub} variable holds the current direction (north, south, east or
     west).

   @{b}*@{ub} The @{b}left@{ub} and @{b}right@{ub} procedures turn the current direction to the left
     and right (respectively) by using some modulo arithmetic trickery.

   @{b}*@{ub} The @{b}move@{ub} procedure uses the @{b}draw@{ub} procedure to draw a line (of length
     @{b}t@{ub}) in the current direction from the current point (stored in @{b}x@{ub}
     and @{b}y@{ub}).

   @{b}*@{ub} The @{b}draw@{ub} procedure draws a line relative to the current point, but
     only if it fits within the boundaries of the window.  The current
     point is moved to the end of the line (even if it isn't drawn).

   @{b}*@{ub} The @{b}main@{ub} procedure reads the command line arguments into the
     variables @{b}m@{ub}, @{b}t@{ub}, @{b}x@{ub} and @{b}y@{ub}.  The depth/size of the dragon is given by @{b}m@{ub}
     (the first argument) and the length of each line making up the dragon
     is given by @{b}t@{ub} (the second argument).  The starting point is given by
     @{b}x@{ub} and @{b}y@{ub} (the final two arguments).  The defaults are five for @{b}m@{ub}
     and @{b}t@{ub}, and zero for @{b}x@{ub} and @{b}y@{ub}.

   @{b}*@{ub} The @{b}main@{ub} procedure also opens the screen and window, and sets the
     dragon drawing.

   @{b}*@{ub} The @{b}dragon@{ub} and @{b}nogard@{ub} procedures are very similar, and these are
     responsible for creating the dragon curve by calling the @{b}left@{ub}, @{b}right@{ub}
     and @{b}move@{ub} procedures.

   @{b}*@{ub} The @{b}dragon@{ub} procedure contains a couple of checks to see if the user
     has pressed Control-C or if the program has run out of stack space,
     raising an appropriate exception if necessary.  These exceptions are
     handled by the @{b}main@{ub} procedure.

Notice the use of @{b}Val@{ub} and the exception handling.  Also, the important
base case of the recursion is when @{b}m@{ub} reaches zero (or becomes negative,
but that shouldn't happen).  If you start off a big dragon and want to
stop it you can press Control-C and the program tidies up nicely.  If it
has finished drawing you simply click the close gadget on the window.


@EndNode

@Node "Common Problems" "beginner.guide/Common Problems"
@Next "Other Information"
@Prev "Recursion Example"
@Toc "Main"

Common Problems
***************

   If you are new to programming or the Amiga E language then you might
appreciate some help locating problems (or @{fg shine}bugs@{fg text}) in your programs.  This
Appendix details some of the most common mistakes people make.


 @{" Assignment and Copying " Link "Assignment and Copying"} 
 @{" Pointers and Memory Allocation " Link "Pointers and Memory Allocation"} 
 @{" String and List Misuse " Link "String and List Misuse"} 
 @{" Initialising Data " Link "Initialising Data"} 
 @{" Freeing Resources " Link "Freeing Resources"} 
 @{" Pointers and Dereferencing " Link "Pointers and Dereferencing"} 
 @{" Mathematics Functions " Link "Mathematics Functions"} 
 @{" Signed and Unsigned Values " Link "Signed and Unsigned Values"} 


@EndNode

@Node "Assignment and Copying" "beginner.guide/Assignment and Copying"
@Next "Pointers and Memory Allocation"
@Toc "Common Problems"

Assignment and Copying
======================

   This is probably the most common problem encountered by people who are
used to languages like BASIC.  Strings, lists, arrays and objects cannot
be initialised using an assignment statement: data must be copied.  Unlike
BASIC, this kind of data is represented by a pointer (see @{"PTR Type" Link "PTR Type"}), so
only the pointer would be copied by an assignment statement, not the data
it points to.  The following examples all copy a pointer rather than the
data, and so the memory for the data is shared (and this is probably not
what was intended).

       DEF s[30]:STRING, t[30]:STRING,
           l[10]:LIST, m[10]:LIST,
           x:myobj, y:myobj,
           a[25]:ARRAY OF INT, b[25]:ARRAY OF INT
     
     /* You probably don't want to do any of these */
       s:='Some text in a string'
       l:=[-6,4,-9]
       x:=[1,2,3]:myobj
       a:=[1,-3,8,7]:INT
     
       t:=s
       m:=l
       y:=x
       b:=a

All the declarations allocate memory for the appropriate data.  The first
four assignments replace the pointers to this memory with pointers to some
statically allocated memory.  The memory allocated by the declarations is
probably now unreachable, because the only pointers to it have been
over-written.  BASIC programmers might expect, say, the assignment to @{b}s@{ub} to
have copied the string into the memory allocated for @{b}s@{ub} by its declaration,
but this is not the case (only the pointer to the string is copied).

   For the E-string, @{b}s@{ub}, and E-list, @{b}l@{ub}, there is another, disastrous
side-effect.  The assignment to @{b}s@{ub}, for example, means that @{b}s@{ub} will point to
a normal string, not an E-string.  So, @{b}s@{ub} can no longer be used with any of
the E-string functions.  The same applies to the E-list, @{b}l@{ub}.

   The final four assignments also copy only the pointers.  This means
that @{b}s@{ub} and @{b}t@{ub} will point to exactly the same memory.  So they will
represent exactly the same string, and any change to one of them (by a
@{b}StrAdd@{ub}, for example) will appear to change both (of course, only one lump
of memory is being changed, but there are two references to it).  This is
called memory @{fg shine}sharing@{fg text}, and is only a problem if you didn't intend to do
it!

   To get the result that a BASIC programmer might have intended you need
to copy the appropriate data.  For E-strings and E-lists the functions to
use are, respectively, @{b}StrCopy@{ub} and @{b}ListCopy@{ub}.  All other data must be
copied using a function like @{b}CopyMem@{ub} (an Amiga system function from the
Exec library).  (Normal strings can be copied using @{b}AstrCopy@{ub} built-in
function, see the `Reference Manual'.) Here's the revised forms of the
above assignments:

       DEF s[30]:STRING, t[30]:STRING,
           l[10]:LIST, m[10]:LIST,
           x:myobj, y:myobj,
           a[25]:ARRAY OF INT, b[25]:ARRAY OF INT
     
       StrCopy(s, 'Some text in a string')  /* Defaults to ALL */
       ListCopy(l, [-6,4,-9])               /* Defaults to ALL */
       CopyMem([1,2,3]:myobj, x, SIZEOF myobj)
       CopyMem([1,-3,8,7]:INT, a, 4*SIZEOF INT)
     
       StrCopy(t, s)   /* Defaults to ALL */
       ListCopy(m, l)  /* Defaults to ALL */
       CopyMem(x, y, SIZEOF myobj)
       CopyMem(a, b, 4*SIZEOF INT)

Notice that you need to supply the size (in bytes) of the data being
copied when you use @{b}CopyMem@{ub}.  The parameters are also given in a slightly
different order to the E-string and E-list copying functions (i.e., the
source must be the first parameter and the destination the second).  The
@{b}CopyMem@{ub} function does a byte-by-byte copy, something like this:

     PROC copymem(src, dest, size)
       DEF i
       FOR i:=1 TO size DO dest[]++:=src[]++
     ENDPROC

   Of course, you can use string constants and lists to give initialised
arrays, but in this case you should be initialising an appropriately typed
pointer.  You must also be careful not to run into a static data problem
(see @{"Static data" Link "Static data"}).

       DEF s:PTR TO CHAR, l:PTR TO LONG, x:PTR TO myobj, a:PTR TO INT
       s:='Some text in a string'
       l:=[-6,4,-9]
       x:=[1,2,3]:myobj
       a:=[1,-3,8,7]:INT


@EndNode

@Node "Pointers and Memory Allocation" "beginner.guide/Pointers and Memory Allocation"
@Next "String and List Misuse"
@Prev "Assignment and Copying"
@Toc "Common Problems"

Pointers and Memory Allocation
==============================

   Another common error is to declare a pointer (usually a pointer to an
object) and then use it without the memory for the target data being
allocated.

     /* You don't want to do this */
       DEF p:PTR TO object
       p.element:=99

There are two ways of correcting this: either dynamically allocate the
memory using @{b}NEW@{ub} or, more simply, let an appropriate declaration allocate
it.  See @{"Memory Allocation" Link "Memory Allocation"}.

       DEF p:PTR TO object
       NEW p
       p.element:=99
     
       DEF p:object
       p.element:=99


@EndNode

@Node "String and List Misuse" "beginner.guide/String and List Misuse"
@Next "Initialising Data"
@Prev "Pointers and Memory Allocation"
@Toc "Common Problems"

String and List Misuse
======================

   Some of the string functions can only be used with E-strings.
Generally, these are the ones that might extend the string.  If you use a
normal string instead you can run into some serious (but subtle) problems.
Commonly misused functions are @{b}ReadStr@{ub}, @{b}MidStr@{ub} and @{b}RightStr@{ub}.  Similar
problems can arise by using a list when an E-list is required by a list
function.

   String constants and normal lists are static data, so you shouldn't try
to alter their contents unless you know what you're doing (see
@{"Static data" Link "Static data"}).


@EndNode

@Node "Initialising Data" "beginner.guide/Initialising Data"
@Next "Freeing Resources"
@Prev "String and List Misuse"
@Toc "Common Problems"

Initialising Data
=================

   Probably one of the most common mistakes that even seasoned programmers
make is to forget to initialise variables (especially pointers).  The
rules in the `Reference Manual' state which declarations initialise
variables to zero values, but it is often wise to make even these explicit
(using initialised declarations).  Variable initialisation becomes even
more important when using automatic exceptions.


@EndNode

@Node "Freeing Resources" "beginner.guide/Freeing Resources"
@Next "Pointers and Dereferencing"
@Prev "Initialising Data"
@Toc "Common Problems"

Freeing Resources
=================

   Unlike a Unix operating system, the Amiga operating system requires the
programmer to release or free any resources used by a program.  In
practice, this means that all windows, screens, libraries, etc., that are
successfully opened must be closed before the program terminates.  Amiga E
provides some help, though: the four most commonly used libraries (Dos,
Exec, Graphics and Intuition) are opened before the start of an E program
and closed at the end (or when @{b}CleanUp@{ub} is called).  Also, memory allocated
using @{b}New@{ub}, @{b}List@{ub} and @{b}String@{ub} is automatically freed at the end of a program.


@EndNode

@Node "Pointers and Dereferencing" "beginner.guide/Pointers and Dereferencing"
@Next "Mathematics Functions"
@Prev "Freeing Resources"
@Toc "Common Problems"

Pointers and Dereferencing
==========================

   C programmers may think that the @{b} ^@{ub}@{fg shine}var@{fg text}@{b}@{ub} and @{b}{@{ub}@{fg shine}var@{fg text} @{b} }@{ub} expressions
are the direct equivalent of C's @{b} &@{ub}@{fg shine}var@{fg text}@{b}@{ub} and @{b} *@{ub}@{fg shine}var@{fg text}@{b}@{ub} expressions.
However, in E dereferencing is normally achieved using array and object
element selection, and pointers to large amounts of data (like E-strings
or objects) are made by declarations.  This means that the @{b} ^@{ub}@{fg shine}var@{fg text}@{b}@{ub} and
@{b}{@{ub}@{fg shine}var@{fg text} @{b} }@{ub} expressions are rarely used, whilst @{b}@{ub}@{fg shine}var@{fg text}@{b}[]@{ub} is very
common.


@EndNode

@Node "Mathematics Functions" "beginner.guide/Mathematics Functions"
@Next "Signed and Unsigned Values"
@Prev "Pointers and Dereferencing"
@Toc "Common Problems"

Mathematics Functions
=====================

   The standard mathematical operators @{b}/@{ub} and @{b}*@{ub} do not use full 32-bit
values in their calculations, as noted previously (see
@{"Maths and logic functions" Link "Maths and logic functions"}).  A common problem is to forget this and use
them where the values will exceed the 16-bit limit.  A typical example is
the position calculations used with proportional gadgets.  See
@{"Signed and Unsigned Values" Link "Signed and Unsigned Values"}.


@EndNode

@Node "Signed and Unsigned Values" "beginner.guide/Signed and Unsigned Values"
@Prev "Mathematics Functions"
@Toc "Common Problems"

Signed and Unsigned Values
==========================

   This is a quite advanced topic, but might be the cause of some strange
bugs in your programs.  Basically, E does not have a way of
differentiating signed and unsigned values from, say, the @{b}LONG@{ub} type.  That
is, all values from the 32-bit, @{b}LONG@{ub} type are considered to be signed
values, so the range of values is from -2,147,483,648 to 2,147,483,647.
If the values from this type were taken to be unsigned then no negative
values would be allowed but more positive values would be possible (i.e.,
the range of values would be from zero to 4,294,967,295).  This
distinction would also affect the mathematical operators.

   In practice, though, it is not the @{b}LONG@{ub} type that can cause problems.
Instead, it is the 16-bit, @{b}INT@{ub} type, which again is considered to be
signed.  This means that the range of values is -32,768 to 32,767.
However, the Amiga system objects contain a number of 16-bit, @{b}INT@{ub} elements
which are actually interpreted as unsigned, ranging from zero to 65,535.
A prominent example is the proportional gadget which forms a part of a
scroll-bar on a window (for example, a drawer window on Workbench).  This
works with unsigned 16-bit values, which is at odds with the @{b}INT@{ub} type in E.
These values are commonly used in calculations to determine the position
of something displayed in a window, and if the @{b}INT@{ub} type is used without
taking into account this signed/unsigned problem the results can be quite
wrong.  Luckily it is quite simple to convert the signed @{b}INT@{ub} values into
unsigned values if they are part of some expression, since the value of
any expression is taken from the @{b}LONG@{ub} type (and unsigned @{b}INT@{ub} values fit
well within the range of even signed @{b}LONG@{ub} values).

     PROC unsigned_int(x) IS x AND $FFFF

   The function @{b}unsigned_int@{ub}, above, is very specific to the way the Amiga
handles values internally, so to understand how it works is beyond the
scope of this Guide.  It should be used wherever an unsigned 16-bit value
is stored in an @{b}INT@{ub} element of, say, an Amiga system object.  For example,
the position of the top of a (vertical) proportional gadget as a
percentage (zero to one hundred) of its size can be calculated like this:

       /* propinfo is from the module 'intuition/intuition' */
       DEF gad:PTR TO propinfo, pct
       /* Set up gad... */
       /* Calculate percentage (MAXPOT is from 'intuition/intuition') */
       pct:=Div(Mul(100,unsigned_int(gad.vertpot)),MAXPOT)

Notice that the full 32-bit functions @{b}Div@{ub} and @{b}Mul@{ub} need to be used since
the arithmetic may be well over the normal 16-bits used in the @{b}/@{ub} and @{b}*@{ub}
operators.

   The remaining type, @{b}CHAR@{ub}, is not, in practice, a problem.  It is the
only unsigned type, with a range of values from zero to 255.  There is a
fairly simple way to convert these values to signed values (and again this
is particular to the way the Amiga stores values internally).  One good
example of a signed @{b}CHAR@{ub} value is the priority value associated with a
node of an Amiga list (i.e., the @{b}pri@{ub} element of an @{b}ln@{ub} object from the
module @{b}exec/nodes@{ub}).

     PROC signed_char(x) IS IF x<128 THEN x ELSE x-256


@EndNode

@Node "Other Information" "beginner.guide/Other Information"
@Next "E Language Index"
@Prev "Common Problems"
@Toc "Main"

Other Information
*****************

   This Appendix contains some useful, miscellaneous information.


 @{" Amiga E Versions " Link "Amiga E Versions"} 
 @{" Further Reading " Link "Further Reading"} 
 @{" Amiga E Author " Link "Amiga E Author"} 
 @{" Guide Author " Link "Guide Author"} 


@EndNode

@Node "Amiga E Versions" "beginner.guide/Amiga E Versions"
@Next "Further Reading"
@Toc "Other Information"

Amiga E Versions
================

   As I write, the current version of Amiga E is version 3.1a (which is
major update of v3.0e).  This edition of the Guide is based primarily on
that version, but the majority still applies to the older versions,
including the last Public Domain version (v2.1b).  Version 3.2 is
imminent, and this Guide is hopefully included with this major update.
See the `Reference Manual' for details of the new features and changes.

   Please note that, as of v3.0a, Amiga E is a commercial product so you
must pay a fee to get a version of the full compiler (which will be
registered to you).  The Public Domain distribution contains only a
demonstration version of the compiler, with limited functionality.  See
the `Reference Manual' for more details.


@EndNode

@Node "Further Reading" "beginner.guide/Further Reading"
@Next "Amiga E Author"
@Prev "Amiga E Versions"
@Toc "Other Information"

Further Reading
===============

`Amiga E Language Reference'
     Referred to as the `Reference Manual' in this Guide.  This is one of
     the documents that comes with the Amiga E package, and is essential
     reading since it was written by Wouter (the author of Amiga E).  It
     contains a lot of extra information.

`Rom Kernel Reference Manual' (Addison-Wesley)
     This is the official Commodore documentation on the Amiga system
     functions and is a must if you want to use these functions properly.
     At the time of writing the Third Edition is the most current and it
     covers the Amiga system functions up to Release 2 (i.e., AmigaDOS
     2.04 and KickStart 37).  Because there is so much information it
     comes in three separate volumes: `Libraries', `Includes and
     Autodocs', and `Devices'.  The `Libraries' volume is probably the
     most useful as it contains many examples and a lot of tutorial
     material.  However, the examples are written mainly in C (the
     remainder are in Assembly).  To alleviate this problem I have
     undertaken to re-code them in E, and Part One of this effort should
     be available from the same place you got this Guide (the archive name
     will be something like @{b}JRH-RKRM-1@{ub}).

`The AmigaDOS Manual' (Bantam Books)
     This is the companion to the `Rom Kernel Reference Manual' and is the
     official Commodore book on AmigaDOS (both the AmigaDOS programs and
     the DOS library functions).  Again, the Third Edition is the most
     current.

Example sources
     Amiga E comes with a large collection of example programs.  When
     you're familiar with the language you should be able to learn quite a
     bit from these.  There are a lot of small, tutorial programs and a
     few large, complicated programs.


@EndNode

@Node "Amiga E Author" "beginner.guide/Amiga E Author"
@Next "Guide Author"
@Prev "Further Reading"
@Toc "Other Information"

Amiga E Author
==============

   In case you didn't know the author and creator of Amiga E is Wouter van
Oortmerssen (or @{b}$#%!@{ub}).  You can reach him by normal mail at the following
address:

     Wouter van Oortmerssen (@{b}$#%!@{ub})
     Levendaal 87
     2311 JG  Leiden
     HOLLAND

However, he much prefers to chat by E-mail, and you can reach him at the
following addresses:

     @{b}Wouter@alf.let.uva.nl@{ub} (E-programming support)
     @{b}Wouter@mars.let.uva.nl@{ub} (personal)
     @{b}Oortmers@gene.fwi.uva.nl@{ub} (other)

Better still, if your problem or enquiry is of general interest to Amiga E
users you may find it useful joining the Amiga E mailing list.  Wouter
regularly contributes to this list and there are a number of good
programmers who are at hand to help or discuss problems.  To join send a
message to:

     @{b}amigae-request@bkhouse.cts.com@{ub}

Once you're subscribed, you will receive a copy of each message mailed to
the list.  You will also receive a message telling you how you can
contribute (i.e., ask questions!).


@EndNode

@Node "Guide Author" "beginner.guide/Guide Author"
@Prev "Amiga E Author"
@Toc "Other Information"

Guide Author
============

   This Guide was written by Jason Hulance, with a lot of help and
guidance from Wouter.  The original aim was to produce something that
might be a useful introduction to Amiga E for beginners, so that the
language could (rightly) become more widespread.  The hidden agenda was to
free Wouter from such a task so that he could concentrate his efforts on
improving Amiga E.

   You can reach me by normal mail most easily at the following (work)
address:

     Jason R. Hulance
     Formal Systems (Europe) Ltd.
     3 Alfred Street
     Oxford
     OX1 4EH
     ENGLAND

Alternatively, you can find me on the Amiga E mailing list, or E-mail me
directly at one of the following addresses:

     @{b}jason@fsel.com@{ub}
     @{b}m88jrh@uk.ac.oxford.ecs@{ub}

If you have any changes or additions you'd like to see then I'd be very
happy to consider them.  Criticism of the text is also welcome, especially
if you can suggest a better way of explaining things.  I am also keen to
hear from people who can highlight areas that are particularly confusing
or badly worded!

   Also, for a small fee you get a printable version of this Guide, in
either DVI or PostScript form.  This includes a huge index, several
pictures and many nice tables, and costs only 5 pounds for UK residents, or
8 pounds for non-UK residents (prices include disk and postage costs).  I
can also make printed versions (including proper binding if required) for
an extra cost.  Please feel free to E-mail or write to me at the above
addresses if you'd like more details.


@EndNode

@Node "E Language Index" "beginner.guide/E Language Index"
@Next "Main Index"
@Prev "Other Information"
@Toc "Main"

E Language Index
****************

   This index should be used to find detailed information about the
keywords, functions, variables and constants which are part of the Amiga E
language.  There is a separate index which deals with concepts etc. (see
@{"Main Index" Link "Main Index"}).



 @{" Symbol, close curly brace " Link "Finding addresses (making pointers)"     0}            Finding addresses (making pointers)
 @{" Symbol, double-quote " Link "Numeric Constants"    11}                 Numeric Constants
 @{" Symbol, open curly brace " Link "Finding addresses (making pointers)"     0}             Finding addresses (making pointers)
 @{" Symbol, ! " Link "Floating-Point Calculations"     0}                            Floating-Point Calculations
 @{" Symbol, $ " Link "Numeric Constants"     0}                            Numeric Constants
 @{" Symbol, % " Link "Numeric Constants"     0}                            Numeric Constants
 @{" Symbol, ' .. ' (string) " Link "Normal strings and E-strings"     0}              Normal strings and E-strings
 @{" Symbol, * " Link "Mathematics"     0}                            Mathematics
 @{" Symbol, + " Link "Mathematics"     0}                            Mathematics
 @{" Symbol, + (strings) " Link "Statements"    57}                  Statements
 @{" Symbol, ++ " Link "Point to other elements"     0}                           Point to other elements
 @{" Symbol, - " Link "Mathematics"     0}                            Mathematics
 @{" Symbol, -- " Link "Point to other elements"     0}                           Point to other elements
 @{" Symbol, -> " Link "Comments"     0}                           Comments
 @{" Symbol, / " Link "Mathematics"     0}                            Mathematics
 @{" Symbol, /* .. */ " Link "Comments"     0}                     Comments
 @{" Symbol, : " Link "Labelling and the JUMP statement"     0}                            Labelling and the JUMP statement
 @{" Symbol, := " Link "Assignment"     0}                           Assignment
 @{" Symbol, ; " Link "Statements"    17}                            Statements
 @{" Symbol, < " Link "Logic and comparison"    11}                            Logic and comparison
 @{" Symbol, <= " Link "Logic and comparison"    11}                           Logic and comparison
 @{" Symbol, <=> " Link "Unification"     0}                          Unification
 @{" Symbol, <> " Link "Logic and comparison"    11}                           Logic and comparison
 @{" Symbol, = " Link "Logic and comparison"    11}                            Logic and comparison
 @{" Symbol, > " Link "Logic and comparison"    11}                            Logic and comparison
 @{" Symbol, >= " Link "Logic and comparison"    11}                           Logic and comparison
 @{" Symbol, [ .. , .. ] (list) " Link "Lists and E-lists"    12}           Lists and E-lists
 @{" Symbol, [ .. , .. ]:type (typed list) " Link "Typed lists"     0} Typed lists
 @{" Symbol, [ .. ] (array) " Link "Tables of data"     0}               Tables of data
 @{" Symbol, [] (array) " Link "Accessing array data"    55}                   Accessing array data
 @{" Symbol, \0 " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Symbol, \a " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Symbol, \b " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Symbol, \c " Link "Input and output functions"    16}                           Input and output functions
 @{" Symbol, \d " Link "Input and output functions"    16}                           Input and output functions
 @{" Symbol, \d " Link "Changing the example"     0}                           Changing the example
 @{" Symbol, \e " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Symbol, \h " Link "Input and output functions"    16}                           Input and output functions
 @{" Symbol, \l " Link "Input and output functions"    53}                           Input and output functions
 @{" Symbol, \n " Link "Strings"     0}                           Strings
 @{" Symbol, \n " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Symbol, \q " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Symbol, \r " Link "Input and output functions"    53}                           Input and output functions
 @{" Symbol, \s " Link "Input and output functions"    16}                           Input and output functions
 @{" Symbol, \t " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Symbol, \z " Link "Input and output functions"    53}                           Input and output functions
 @{" Symbol, \\ " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Symbol, ^ " Link "Extracting data (dereferencing pointers)"     0}                            Extracting data (dereferencing pointers)
 @{" Symbol, ` (backquote) " Link "Quoted Expressions"     0}                Quoted Expressions
 @{" Abs " Link "Maths and logic functions"    30}                                  Maths and logic functions
 @{" ALL " Link "Built-In Constants"    12}                                  Built-In Constants
 @{" AND " Link "Bitwise AND and OR"     0}                                  Bitwise AND and OR
 @{" And " Link "Maths and logic functions"    14}                                  Maths and logic functions
 @{" arg " Link "Built-In Variables"     7}                                  Built-In Variables
 @{" ARRAY " Link "Tables of data"     0}                                Tables of data
 @{" ARRAY OF type " Link "Tables of data"     0}                        Tables of data
 @{" Bounds " Link "Maths and logic functions"    54}                               Maths and logic functions
 @{" Box " Link "Graphics functions"    30}                                  Graphics functions
 @{" BUT " Link "BUT expression"     0}                                  BUT expression
 @{" CASE " Link "SELECT..OF block"     0}                                 SELECT..OF block
 @{" CASE " Link "SELECT block"     0}                                 SELECT block
 @{" CASE ..TO.. " Link "SELECT..OF block"     0}                          SELECT..OF block
 @{" Char " Link "Maths and logic functions"   114}                                 Maths and logic functions
 @{" CHAR " Link "Static memory"     0}                                 Static memory
 @{" CHAR " Link "Indirect types"     0}                                 Indirect types
 @{" CleanUp " Link "System support functions"    64}                              System support functions
 @{" CloseS " Link "Intuition support functions"   178}                               Intuition support functions
 @{" CloseW " Link "Intuition support functions"   122}                               Intuition support functions
 @{" Colour " Link "Graphics functions"    35}                               Graphics functions
 @{" conout " Link "Built-In Variables"    34}                               Built-In Variables
 @{" CONST " Link "Named Constants"     0}                                Named Constants
 @{" CtrlC " Link "System support functions"    73}                                System support functions
 @{" DEC " Link "INC and DEC statements"     0}                                  INC and DEC statements
 @{" DEF " Link "Variable declaration"     0}                                  Variable declaration
 @{" DEFAULT " Link "SELECT block"     0}                              SELECT block
 @{" DEFAULT " Link "SELECT..OF block"     0}                              SELECT..OF block
 @{" Dispose " Link "System support functions"    38}                              System support functions
 @{" DisposeLink " Link "System support functions"    43}                          System support functions
 @{" Div " Link "Maths and logic functions"     0}                                  Maths and logic functions
 @{" DO, (FOR loop) " Link "FOR loop"    55}                       FOR loop
 @{" DO, (WHILE loop) " Link "WHILE loop"    57}                     WHILE loop
 @{" dosbase " Link "Built-In Variables"    51}                              Built-In Variables
 @{" ELSE " Link "IF block"     0}                                 IF block
 @{" ELSEIF " Link "IF block"     0}                               IF block
 @{" EMPTY " Link "Inheritance in E"   275}                                Inheritance in E
 @{" end " Link "Methods in E"   118}                                  Methods in E
 @{" END " Link "NEW and END Operators"     0}                                  NEW and END Operators
 @{" ENDFOR " Link "FOR loop"     0}                               FOR loop
 @{" ENDIF " Link "IF block"     0}                                IF block
 @{" ENDLOOP " Link "LOOP block"     0}                              LOOP block
 @{" ENDOBJECT " Link "Example object"    23}                            Example object
 @{" ENDPROC " Link "Procedure Definition"     0}                              Procedure Definition
 @{" ENDPROC value " Link "Functions"    24}                        Functions
 @{" ENDSELECT " Link "SELECT..OF block"     0}                            SELECT..OF block
 @{" ENDSELECT " Link "SELECT block"     0}                            SELECT block
 @{" ENDWHILE " Link "WHILE loop"     0}                             WHILE loop
 @{" ENUM " Link "Enumerations"     0}                                 Enumerations
 @{" Eor " Link "Maths and logic functions"    14}                                  Maths and logic functions
 @{" EstrLen " Link "String functions"   122}                              String functions
 @{" Eval " Link "Evaluation"     0}                                 Evaluation
 @{" Even " Link "Maths and logic functions"    40}                                 Maths and logic functions
 @{" EXCEPT " Link "Procedures with Exception Handlers"     0}                               Procedures with Exception Handlers
 @{" EXCEPT DO " Link "Raising an Exception"    73}                            Raising an Exception
 @{" exception " Link "Raising an Exception"    36}                            Raising an Exception
 @{" exceptioninfo " Link "Raising an Exception"    50}                        Raising an Exception
 @{" execbase " Link "Built-In Variables"    51}                             Built-In Variables
 @{" Exists " Link "Lists and quoted expressions"    46}                               Lists and quoted expressions
 @{" EXIT " Link "EXIT statement"     0}                                 EXIT statement
 @{" Fabs " Link "Floating-Point Functions"    55}                                 Floating-Point Functions
 @{" FALSE " Link "Built-In Constants"     5}                                Built-In Constants
 @{" FALSE " Link "Logic and comparison"    11}                                Logic and comparison
 @{" FastDispose " Link "System support functions"    58}                          System support functions
 @{" FastDisposeList " Link "List and typed list allocation"    66}                      List and typed list allocation
 @{" FastNew " Link "System support functions"    49}                              System support functions
 @{" Fceil " Link "Floating-Point Functions"    59}                                Floating-Point Functions
 @{" Fcos " Link "Floating-Point Functions"    51}                                 Floating-Point Functions
 @{" Fexp " Link "Floating-Point Functions"    66}                                 Floating-Point Functions
 @{" Ffloor " Link "Floating-Point Functions"    59}                               Floating-Point Functions
 @{" FileLength " Link "Input and output functions"   150}                           Input and output functions
 @{" Flog " Link "Floating-Point Functions"    73}                                 Floating-Point Functions
 @{" Flog10 " Link "Floating-Point Functions"    73}                               Floating-Point Functions
 @{" FOR " Link "FOR loop"     0}                                  FOR loop
 @{" ForAll " Link "Lists and quoted expressions"    29}                               Lists and quoted expressions
 @{" Forward " Link "Linked Lists"    54}                              Linked Lists
 @{" Fpow " Link "Floating-Point Functions"    66}                                 Floating-Point Functions
 @{" FreeStack " Link "System support functions"    78}                            System support functions
 @{" Fsin " Link "Floating-Point Functions"    51}                                 Floating-Point Functions
 @{" Fsqrt " Link "Floating-Point Functions"    63}                                Floating-Point Functions
 @{" Ftan " Link "Floating-Point Functions"    51}                                 Floating-Point Functions
 @{" Gadget " Link "Intuition support functions"   187}                               Intuition support functions
 @{" GADGETSIZE " Link "Built-In Constants"    16}                           Built-In Constants
 @{" gfxbase " Link "Built-In Variables"    51}                              Built-In Variables
 @{" HANDLE " Link "Procedures with Exception Handlers"     0}                               Procedures with Exception Handlers
 @{" IF " Link "IF block"     0}                                   IF block
 @{" IF, (expression) " Link "IF expression"     0}                     IF expression
 @{" INC " Link "INC and DEC statements"     0}                                  INC and DEC statements
 @{" INCBIN " Link "Static memory"     0}                               Static memory
 @{" Inp " Link "Input and output functions"   105}                                  Input and output functions
 @{" InStr " Link "String functions"   153}                                String functions
 @{" INT " Link "Indirect types"     0}                                  Indirect types
 @{" INT " Link "Static memory"     0}                                  Static memory
 @{" Int " Link "Maths and logic functions"   114}                                  Maths and logic functions
 @{" intuitionbase " Link "Built-In Variables"    51}                        Built-In Variables
 @{" IS " Link "One-Line Functions"     0}                                   One-Line Functions
 @{" JUMP " Link "Labelling and the JUMP statement"     0}                                 Labelling and the JUMP statement
 @{" KickVersion " Link "System support functions"    83}                          System support functions
 @{" LeftMouse " Link "Intuition support functions"   276}                            Intuition support functions
 @{" Line " Link "Graphics functions"    27}                                 Graphics functions
 @{" Link " Link "Linked Lists"    23}                                 Linked Lists
 @{" LIST " Link "Lists and E-lists"    35}                                 Lists and E-lists
 @{" List " Link "List functions"    12}                                 List functions
 @{" ListAdd " Link "List functions"    47}                              List functions
 @{" ListCmp " Link "List functions"    28}                              List functions
 @{" ListCopy " Link "List functions"    37}                             List functions
 @{" ListItem " Link "List functions"    65}                             List functions
 @{" ListLen " Link "List functions"    55}                              List functions
 @{" ListMax " Link "List functions"    59}                              List functions
 @{" LONG " Link "Static memory"     0}                                 Static memory
 @{" Long " Link "Maths and logic functions"   114}                                 Maths and logic functions
 @{" LONG " Link "LONG Type"     0}                                 LONG Type
 @{" LONG, preliminary " Link "Variable types"     0}                    Variable types
 @{" LOOP " Link "LOOP block"     0}                                 LOOP block
 @{" LowerStr " Link "String functions"   166}                             String functions
 @{" main " Link "Procedures"     0}                                 Procedures
 @{" MapList " Link "Lists and quoted expressions"     8}                              Lists and quoted expressions
 @{" Max " Link "Maths and logic functions"    48}                                  Maths and logic functions
 @{" MidStr " Link "String functions"   141}                               String functions
 @{" Min " Link "Maths and logic functions"    51}                                  Maths and logic functions
 @{" Mod " Link "Maths and logic functions"    69}                                  Maths and logic functions
 @{" MODULE " Link "Using Modules"     0}                               Using Modules
 @{" Mouse " Link "Intuition support functions"   235}                                Intuition support functions
 @{" MouseX " Link "Intuition support functions"   256}                               Intuition support functions
 @{" MouseY " Link "Intuition support functions"   266}                               Intuition support functions
 @{" MsgCode " Link "Intuition support functions"   316}                              Intuition support functions
 @{" Mul " Link "Maths and logic functions"     0}                                  Maths and logic functions
 @{" NEW " Link "NEW and END Operators"     0}                                  NEW and END Operators
 @{" New " Link "System support functions"     0}                                  System support functions
 @{" NEWFILE " Link "Built-In Constants"    20}                              Built-In Constants
 @{" NewM " Link "System support functions"    19}                                 System support functions
 @{" NewR " Link "System support functions"    14}                                 System support functions
 @{" Next " Link "Linked Lists"    36}                                 Linked Lists
 @{" NIL " Link "Built-In Constants"     8}                                  Built-In Constants
 @{" Not " Link "Maths and logic functions"    14}                                  Maths and logic functions
 @{" OBJECT " Link "Example object"    23}                               Example object
 @{" OBJECT..OF " Link "Inheritance in E"     0}                           Inheritance in E
 @{" Odd " Link "Maths and logic functions"    44}                                  Maths and logic functions
 @{" OLDFILE " Link "Built-In Constants"    20}                              Built-In Constants
 @{" OpenS " Link "Intuition support functions"   129}                                Intuition support functions
 @{" OpenW " Link "Intuition support functions"    16}                                Intuition support functions
 @{" Or " Link "Maths and logic functions"    14}                                   Maths and logic functions
 @{" OR " Link "Bitwise AND and OR"     0}                                   Bitwise AND and OR
 @{" Out " Link "Input and output functions"    97}                                  Input and output functions
 @{" Plot " Link "Graphics functions"    16}                                 Graphics functions
 @{" PrintF " Link "Input and output functions"    83}                               Input and output functions
 @{" PRIVATE " Link "Data-Hiding in E"     0}                              Data-Hiding in E
 @{" PROC " Link "Procedure Definition"     0}                                 Procedure Definition
 @{" PROC..OF " Link "Methods in E"     0}                             Methods in E
 @{" PTR TO type " Link "PTR Type"     0}                          PTR Type
 @{" PUBLIC " Link "Data-Hiding in E"     0}                               Data-Hiding in E
 @{" PutChar " Link "Maths and logic functions"   121}                              Maths and logic functions
 @{" PutInt " Link "Maths and logic functions"   121}                               Maths and logic functions
 @{" PutLong " Link "Maths and logic functions"   121}                              Maths and logic functions
 @{" RAISE " Link "Automatic Exceptions"    25}                                Automatic Exceptions
 @{" Raise " Link "Raising an Exception"     0}                                Raising an Exception
 @{" ReadStr " Link "Input and output functions"   110}                              Input and output functions
 @{" RealF " Link "Floating-Point Functions"    19}                                Floating-Point Functions
 @{" RealVal " Link "Floating-Point Functions"    10}                              Floating-Point Functions
 @{" REPEAT " Link "REPEAT..UNTIL loop"     0}                               REPEAT..UNTIL loop
 @{" RETURN " Link "Functions"    33}                               Functions
 @{" RightStr " Link "String functions"   133}                             String functions
 @{" Rnd " Link "Maths and logic functions"    83}                                  Maths and logic functions
 @{" RndQ " Link "Maths and logic functions"    92}                                 Maths and logic functions
 @{" SELECT " Link "SELECT..OF block"     0}                               SELECT..OF block
 @{" SELECT " Link "SELECT block"     0}                               SELECT block
 @{" SELECT..OF " Link "SELECT..OF block"     0}                           SELECT..OF block
 @{" SelectList " Link "Lists and quoted expressions"    62}                           Lists and quoted expressions
 @{" self " Link "Methods in E"    67}                                 Methods in E
 @{" SET " Link "Sets"     0}                                  Sets
 @{" SetColour " Link "Graphics functions"    48}                            Graphics functions
 @{" SetList " Link "List functions"    62}                              List functions
 @{" SetStdIn " Link "Input and output functions"   157}                             Input and output functions
 @{" SetStdOut " Link "Input and output functions"   166}                            Input and output functions
 @{" SetStdRast " Link "Graphics functions"    57}                           Graphics functions
 @{" SetStr " Link "String functions"   175}                               String functions
 @{" SetTopaz " Link "Graphics functions"    66}                             Graphics functions
 @{" Shl " Link "Maths and logic functions"    99}                                  Maths and logic functions
 @{" Shr " Link "Maths and logic functions"   107}                                  Maths and logic functions
 @{" Sign " Link "Maths and logic functions"    35}                                 Maths and logic functions
 @{" SIZEOF " Link "SIZEOF expression"     0}                               SIZEOF expression
 @{" stdin " Link "Built-In Variables"    34}                                Built-In Variables
 @{" stdout " Link "Built-In Variables"    34}                               Built-In Variables
 @{" stdrast " Link "Built-In Variables"    46}                              Built-In Variables
 @{" STEP " Link "FOR loop"    37}                                 FOR loop
 @{" StrAdd " Link "String functions"    96}                               String functions
 @{" StrCmp " Link "String functions"    37}                               String functions
 @{" StrCopy " Link "String functions"    55}                              String functions
 @{" STRING " Link "Normal strings and E-strings"    49}                               Normal strings and E-strings
 @{" String " Link "String functions"    14}                               String functions
 @{" StringF " Link "Input and output functions"    88}                              Input and output functions
 @{" StrLen " Link "String functions"   105}                               String functions
 @{" STRLEN " Link "Built-In Constants"    24}                               Built-In Constants
 @{" StrMax " Link "String functions"   128}                               String functions
 @{" SUPER " Link "Inheritance in E"   110}                                Inheritance in E
 @{" TextF " Link "Graphics functions"    42}                                Graphics functions
 @{" THEN " Link "IF block"    29}                                 IF block
 @{" Throw " Link "Raising an Exception"     0}                                Raising an Exception
 @{" TO " Link "FOR loop"     0}                                   FOR loop
 @{" TO, (CASE range) " Link "SELECT..OF block"     0}                     SELECT..OF block
 @{" TO, (FOR loop) " Link "FOR loop"     0}                       FOR loop
 @{" TrimStr " Link "String functions"   158}                              String functions
 @{" TRUE " Link "Logic and comparison"    11}                                 Logic and comparison
 @{" TRUE " Link "Built-In Constants"     5}                                 Built-In Constants
 @{" UNTIL " Link "REPEAT..UNTIL loop"     0}                                REPEAT..UNTIL loop
 @{" UpperStr " Link "String functions"   171}                             String functions
 @{" Val " Link "String functions"   195}                                  String functions
 @{" VOID " Link "Turning an Expression into a Statement"     0}                                 Turning an Expression into a Statement
 @{" WaitIMessage " Link "Intuition support functions"   285}                         Intuition support functions
 @{" WaitLeftMouse " Link "Intuition support functions"   327}                        Intuition support functions
 @{" wbmessage " Link "Built-In Variables"    23}                            Built-In Variables
 @{" WHILE " Link "WHILE loop"     0}                                WHILE loop
 @{" WriteF " Link "Input and output functions"     0}                               Input and output functions


@EndNode

@Node "Main Index" "beginner.guide/Main Index"
@Prev "E Language Index"
@Toc "Main"

Main Index
**********

   This index should be used to find detailed information about particular
concepts.  There is a separate index which deals with the keywords,
variables, functions and constants which are part of Amiga E (see
@{"E Language Index" Link "E Language Index"}).

@Index "Main Index"



 @{" A4 register " Link "Things to watch out for"    11}                          Things to watch out for
 @{" A5 register " Link "Things to watch out for"    11}                          Things to watch out for
 @{" Absolute value " Link "Maths and logic functions"    30}                       Maths and logic functions
 @{" Absolute value (floating-point) " Link "Floating-Point Functions"    55}      Floating-Point Functions
 @{" Abstract class " Link "Inheritance in E"   173}                       Inheritance in E
 @{" Abstract method " Link "Inheritance in E"   275}                      Inheritance in E
 @{" Access array outside bounds " Link "Accessing array data"    25}          Accessing array data
 @{" Accessing array data " Link "Accessing array data"     0}                 Accessing array data
 @{" Accuracy of floating-point numbers " Link "Accuracy and Range"     0}   Accuracy and Range
 @{" Addition " Link "Mathematics"     0}                             Mathematics
 @{" Address " Link "Addresses"     0}                              Addresses
 @{" Address " Link "Memory addresses"     0}                              Memory addresses
 @{" Address, finding " Link "Finding addresses (making pointers)"     0}                     Finding addresses (making pointers)
 @{" Algebra " Link "Variables and Expressions"     0}                              Variables and Expressions
 @{" Alignment " Link "SIZEOF expression"    17}                            SIZEOF expression
 @{" Allocating an object " Link "Objects in E"    17}                 Objects in E
 @{" Allocating memory " Link "System support functions"     0}                    System support functions
 @{" Allocation, dynamic memory " Link "Dynamic Allocation"     0}           Dynamic Allocation
 @{" Allocation, memory " Link "Memory Allocation"     0}                   Memory Allocation
 @{" Allocation, static memory " Link "Static Allocation"     0}            Static Allocation
 @{" Allocation, typed memory dynamically " Link "NEW and END Operators"     0} NEW and END Operators
 @{" Allowable assignment left-hand sides " Link "Assignments"    33} Assignments
 @{" Amiga E author " Link "Amiga E Author"     0}                       Amiga E Author
 @{" Amiga system module " Link "Amiga System Modules"     0}                  Amiga System Modules
 @{" Amiga system objects " Link "Amiga system objects"     0}                 Amiga system objects
 @{" Analogy, pointers " Link "Addresses"     0}                    Addresses
 @{" And " Link "Maths and logic functions"    14}                                  Maths and logic functions
 @{" AND, bit-wise " Link "Bitwise AND and OR"     0}                        Bitwise AND and OR
 @{" AND-ing flags " Link "Sets"    19}                        Sets
 @{" Apostrophe " Link "String Constants Special Character Sequences"     0}                           String Constants Special Character Sequences
 @{" Append to a list " Link "List functions"    47}                     List functions
 @{" Append to an E-string " Link "String functions"    96}                String functions
 @{" arg, using " Link "Any AmigaDOS"     0}                           Any AmigaDOS
 @{" Argument " Link "Parameters"     0}                             Parameters
 @{" Argument parsing " Link "Argument Parsing"     0}                     Argument Parsing
 @{" Argument, default " Link "Default Arguments"     0}                    Default Arguments
 @{" Array " Link "Tables of data"     0}                                Tables of data
 @{" Array and array pointer declaration " Link "Array pointers"    46}  Array pointers
 @{" Array diagram " Link "Array pointers"    71}                        Array pointers
 @{" Array pointer, decrementing " Link "Point to other elements"     0}          Point to other elements
 @{" Array pointer, incrementing " Link "Point to other elements"     0}          Point to other elements
 @{" Array pointer, next element " Link "Point to other elements"     0}          Point to other elements
 @{" Array pointer, previous element " Link "Point to other elements"     0}      Point to other elements
 @{" Array size " Link "Tables of data"     0}                           Tables of data
 @{" Array, access outside bounds " Link "Accessing array data"    25}         Accessing array data
 @{" Array, accessing data " Link "Accessing array data"     0}                Accessing array data
 @{" Array, first element short-hand " Link "Accessing array data"    55}      Accessing array data
 @{" Array, initialised " Link "Typed lists"     0}                   Typed lists
 @{" Array, pointer " Link "Array pointers"     0}                       Array pointers
 @{" Array, procedure parameter " Link "Array procedure parameters"     0}           Array procedure parameters
 @{" ASCII character constant " Link "Numeric Constants"    11}             Numeric Constants
 @{" Assembly and E constants " Link "Assembly and the E language"    15}             Assembly and the E language
 @{" Assembly and E variables " Link "Assembly and the E language"     0}             Assembly and the E language
 @{" Assembly and labels " Link "Assembly and the E language"    28}                  Assembly and the E language
 @{" Assembly and procedures " Link "Assembly and the E language"    28}              Assembly and the E language
 @{" Assembly and static memory " Link "Static memory"     0}           Static memory
 @{" Assembly statements " Link "Assembly Statements"     0}                  Assembly Statements
 @{" Assembly, calling system functions " Link "Assembly and the E language"    39}   Assembly and the E language
 @{" Assembly, potential problems " Link "Things to watch out for"     0}         Things to watch out for
 @{" Assignment expression " Link "Assignments"     0}                Assignments
 @{" Assignment versus copying " Link "String functions"    67}            String functions
 @{" Assignment, := " Link "Assignment"     0}                       Assignment
 @{" Assignment, allowable left-hand sides " Link "Assignments"    33} Assignments
 @{" Assignment, Emodules: " Link "Using Modules"     0}                Using Modules
 @{" Assignment, multiple " Link "Multiple Return Values"    12}                 Multiple Return Values
 @{" Automatic exceptions " Link "Automatic Exceptions"     0}                 Automatic Exceptions
 @{" Automatic exceptions and initialisation " Link "Raise within an Exception Handler"    54} Raise within an Exception Handler
 @{" Automatic voiding " Link "Turning an Expression into a Statement"    20}                    Turning an Expression into a Statement
 @{" Background pen, setting colour " Link "Graphics functions"    35}       Graphics functions
 @{" Backslash " Link "String Constants Special Character Sequences"     0}                            String Constants Special Character Sequences
 @{" Base case " Link "Factorial Example"    44}                            Factorial Example
 @{" Base class " Link "Inheritance"     0}                           Inheritance
 @{" Beginner's Guide author " Link "Guide Author"     0}              Guide Author
 @{" Binary constant " Link "Numeric Constants"     0}                      Numeric Constants
 @{" Binary tree " Link "Binary Trees"     0}                          Binary Trees
 @{" Bit shift left " Link "Maths and logic functions"    99}                       Maths and logic functions
 @{" Bit shift right " Link "Maths and logic functions"   107}                      Maths and logic functions
 @{" Bit-wise AND and OR " Link "Bitwise AND and OR"     0}                  Bitwise AND and OR
 @{" Black box " Link "Classes and methods"     0}                            Classes and methods
 @{" Block, conditional " Link "Conditional Block"     0}                   Conditional Block
 @{" Block, IF " Link "IF block"     0}                            IF block
 @{" Block, SELECT " Link "SELECT block"     0}                        SELECT block
 @{" Block, SELECT..OF " Link "SELECT..OF block"     0}                    SELECT..OF block
 @{" Books, further reading " Link "Further Reading"     0}               Further Reading
 @{" Bounding a value " Link "Maths and logic functions"    54}                     Maths and logic functions
 @{" Box drawing " Link "Graphics functions"    30}                          Graphics functions
 @{" Box, black " Link "Classes and methods"     0}                           Classes and methods
 @{" Bracketing expressions " Link "Precedence and grouping"     0}               Precedence and grouping
 @{" Branch " Link "Binary Trees"     0}                               Binary Trees
 @{" Breaking a string over several lines " Link "Statements"    57} Statements
 @{" Breaking statements over several lines " Link "Statements"    29} Statements
 @{" Bug, finding " Link "Common Problems"     0}                         Common Problems
 @{" Built-in constants " Link "Built-In Constants"     0}                   Built-In Constants
 @{" Built-in functions " Link "Built-In Functions"     0}                   Built-In Functions
 @{" Built-in functions, floating-point " Link "Floating-Point Functions"     0}   Floating-Point Functions
 @{" Built-in functions, linked list " Link "Linked Lists"    13}      Linked Lists
 @{" Built-in functions, list and E-list " Link "List functions"     0}  List functions
 @{" Built-in functions, string and E-string " Link "String functions"     0} String functions
 @{" Built-in variables " Link "Built-In Variables"     0}                   Built-In Variables
 @{" BUT expression " Link "BUT expression"     0}                       BUT expression
 @{" Button click, left " Link "Intuition support functions"   276}                   Intuition support functions
 @{" Button click, left (wait) " Link "Intuition support functions"   327}            Intuition support functions
 @{" Buttons state " Link "Intuition support functions"   235}                        Intuition support functions
 @{" Calculating with floating-point numbers " Link "Floating-Point Calculations"     0} Floating-Point Calculations
 @{" Calling a method " Link "Methods in E"    28}                     Methods in E
 @{" Calling a procedure " Link "Procedures"     0}                  Procedures
 @{" Calling a procedure " Link "Procedure Execution"     0}                  Procedure Execution
 @{" Calling system functions from Assembly " Link "Assembly and the E language"    39} Assembly and the E language
 @{" Carriage return " Link "String Constants Special Character Sequences"     0}                      String Constants Special Character Sequences
 @{" Case of characters in identifiers " Link "Identifiers"     0}    Identifiers
 @{" Case, base " Link "Factorial Example"    44}                           Factorial Example
 @{" Case, recursive " Link "Factorial Example"    44}                      Factorial Example
 @{" Ceiling of a floating-point value " Link "Floating-Point Functions"    59}    Floating-Point Functions
 @{" Changing stdin " Link "Input and output functions"   157}                       Input and output functions
 @{" Changing stdout " Link "Input and output functions"   166}                      Input and output functions
 @{" Changing stdrast " Link "Graphics functions"    57}                     Graphics functions
 @{" Changing the value of a variable " Link "Assignment"     0}     Assignment
 @{" Character constant " Link "Numeric Constants"    11}                   Numeric Constants
 @{" Character, apostrophe " Link "String Constants Special Character Sequences"     0}                String Constants Special Character Sequences
 @{" Character, backslash " Link "String Constants Special Character Sequences"     0}                 String Constants Special Character Sequences
 @{" Character, carriage return " Link "String Constants Special Character Sequences"     0}           String Constants Special Character Sequences
 @{" Character, double quote " Link "String Constants Special Character Sequences"     0}              String Constants Special Character Sequences
 @{" Character, escape " Link "String Constants Special Character Sequences"     0}                    String Constants Special Character Sequences
 @{" Character, linefeed " Link "String Constants Special Character Sequences"     0}                  String Constants Special Character Sequences
 @{" Character, null " Link "String Constants Special Character Sequences"     0}                      String Constants Special Character Sequences
 @{" Character, printing " Link "Input and output functions"     0}                  Input and output functions
 @{" Character, read from a file " Link "Input and output functions"   105}          Input and output functions
 @{" Character, tab " Link "String Constants Special Character Sequences"     0}                       String Constants Special Character Sequences
 @{" Character, write to file " Link "Input and output functions"    97}             Input and output functions
 @{" Choice, conditional block " Link "Conditional Block"     0}            Conditional Block
 @{" Class (OOP) " Link "Classes and methods"     0}                          Classes and methods
 @{" Class hierarchy " Link "Inheritance in E"   173}                      Inheritance in E
 @{" Class, abstract " Link "Inheritance in E"   173}                      Inheritance in E
 @{" Class, base " Link "Inheritance"     0}                          Inheritance
 @{" Class, derived " Link "Inheritance"     0}                       Inheritance
 @{" Class, super " Link "Inheritance in E"   161}                         Inheritance in E
 @{" Classes and modules " Link "Data-Hiding in E"     0}                  Data-Hiding in E
 @{" Clean-up, program termination " Link "System support functions"    64}        System support functions
 @{" Close screen " Link "Intuition support functions"   178}                         Intuition support functions
 @{" Close window " Link "Intuition support functions"   122}                         Intuition support functions
 @{" Code fragment " Link "Conditional Block"     0}                        Conditional Block
 @{" Code modules " Link "Code Modules"     0}                         Code Modules
 @{" code part of Intuition message " Link "Intuition support functions"   316}       Intuition support functions
 @{" Code, reuse " Link "Style Reuse and Readability"     0}                          Style Reuse and Readability
 @{" Code, style " Link "Style Reuse and Readability"     0}                          Style Reuse and Readability
 @{" Colour, setting " Link "Graphics functions"    48}                      Graphics functions
 @{" Colour, setting foreground and background pen " Link "Graphics functions"    35} Graphics functions
 @{" Command line argument parsing " Link "Argument Parsing"     0}        Argument Parsing
 @{" Comment, nested " Link "Comments"     7}                      Comments
 @{" Comments " Link "Comments"     0}                             Comments
 @{" Common logarithm " Link "Floating-Point Functions"    73}                     Floating-Point Functions
 @{" Common problems " Link "Common Problems"     0}                      Common Problems
 @{" Common use of pointers " Link "Extracting data (dereferencing pointers)"    89}               Extracting data (dereferencing pointers)
 @{" Comparison of lists " Link "List functions"    28}                  List functions
 @{" Comparison of strings " Link "String functions"    37}                String functions
 @{" Comparison operators " Link "Logic and comparison"    11}                 Logic and comparison
 @{" Compiler, ec " Link "Compilation"     0}                         Compilation
 @{" Complex memory, deallocate " Link "System support functions"    43}           System support functions
 @{" Complex memory, free " Link "System support functions"    43}                 System support functions
 @{" Complex types " Link "Complex types"     0}                        Complex types
 @{" Conditional block " Link "Conditional Block"     0}                    Conditional Block
 @{" Constant " Link "Constants"     0}                             Constants
 @{" Constant string " Link "Normal strings and E-strings"     0}                      Normal strings and E-strings
 @{" Constant, binary " Link "Numeric Constants"     0}                     Numeric Constants
 @{" Constant, built-in " Link "Built-In Constants"     0}                   Built-In Constants
 @{" Constant, character " Link "Numeric Constants"    11}                  Numeric Constants
 @{" Constant, decimal " Link "Numeric Constants"     0}                    Numeric Constants
 @{" Constant, enumeration " Link "Enumerations"     0}                Enumerations
 @{" Constant, hexadecimal " Link "Numeric Constants"     0}                Numeric Constants
 @{" Constant, named " Link "Named Constants"     0}                      Named Constants
 @{" Constant, numeric " Link "Numeric Constants"     0}                    Numeric Constants
 @{" Constant, set " Link "Sets"     0}                        Sets
 @{" Constant, use in Assembly " Link "Assembly and the E language"    15}            Assembly and the E language
 @{" Constructor " Link "Classes and methods"    20}                          Classes and methods
 @{" Constructor, names " Link "Methods in E"    78}                   Methods in E
 @{" Control-C testing " Link "System support functions"    73}                    System support functions
 @{" Controlling program flow " Link "Program Flow Control"     0}             Program Flow Control
 @{" Conversion of floating-point numbers " Link "Floating-Point Calculations"     0} Floating-Point Calculations
 @{" Convert an expression to a statement " Link "Turning an Expression into a Statement"     0} Turning an Expression into a Statement
 @{" Convert header file to module " Link "Non-Standard Modules"     0}        Non-Standard Modules
 @{" Convert include file to module " Link "Non-Standard Modules"     0}       Non-Standard Modules
 @{" Convert pragma file to module " Link "Non-Standard Modules"     0}        Non-Standard Modules
 @{" Converting floating-point numbers from a string " Link "Floating-Point Functions"    10} Floating-Point Functions
 @{" Converting strings to numbers " Link "String functions"   195}        String functions
 @{" Copy middle part of a string " Link "String functions"   141}         String functions
 @{" Copy right-hand part of an E-string " Link "String functions"   133}  String functions
 @{" Copying a list " Link "List functions"    37}                       List functions
 @{" Copying a string " Link "String functions"    55}                     String functions
 @{" Copying versus assignment " Link "String functions"    67}            String functions
 @{" Cosine function " Link "Floating-Point Functions"    51}                      Floating-Point Functions
 @{" Crash, avoiding stack problems " Link "Stack (and Crashing)"    21}       Stack (and Crashing)
 @{" Crash, running out of stack " Link "Stack (and Crashing)"     0}          Stack (and Crashing)
 @{" Create gadget " Link "Intuition support functions"   187}                        Intuition support functions
 @{" Cure for linefeed problem " Link "Strings"     0}            Strings
 @{" Data, extracting from a pointer " Link "Extracting data (dereferencing pointers)"     0}      Extracting data (dereferencing pointers)
 @{" Data, input " Link "The Simple Program"     0}                          The Simple Program
 @{" Data, manipulation " Link "The Simple Program"     0}                   The Simple Program
 @{" Data, named " Link "Variables and Expressions"     0}                          Variables and Expressions
 @{" Data, output " Link "The Simple Program"     0}                         The Simple Program
 @{" Data, static " Link "Static data"     0}                         Static data
 @{" Data, storage " Link "Variable types"     0}                        Variable types
 @{" Data-abstraction " Link "Classes and methods"    29}                     Classes and methods
 @{" Data-hiding " Link "Classes and methods"    29}                          Classes and methods
 @{" Deallocating an object " Link "Objects in E"    31}               Objects in E
 @{" Deallocating complex memory " Link "System support functions"    43}          System support functions
 @{" Deallocating memory " Link "System support functions"    38}                  System support functions
 @{" Deallocation of memory " Link "Deallocation of Memory"     0}               Deallocation of Memory
 @{" Deallocation, potential problems " Link "Deallocation of Memory"    28}     Deallocation of Memory
 @{" Decimal constant " Link "Numeric Constants"     0}                     Numeric Constants
 @{" Decimal number, printing " Link "Input and output functions"     0}             Input and output functions
 @{" Decision, conditional block " Link "Conditional Block"     0}          Conditional Block
 @{" Declaration, array and array pointer " Link "Array pointers"    46} Array pointers
 @{" Declaration, illegal " Link "Indirect types"     0}                 Indirect types
 @{" Declaration, initialised " Link "Initialised Declarations"     0}             Initialised Declarations
 @{" Declaration, variable type " Link "Default type"    15}           Default type
 @{" Declaring a variable " Link "Variable declaration"     0}                 Variable declaration
 @{" Decrementing a variable " Link "INC and DEC statements"     0}              INC and DEC statements
 @{" Decrementing array pointer " Link "Point to other elements"     0}           Point to other elements
 @{" Default arguments " Link "Default Arguments"     0}                    Default Arguments
 @{" Default type " Link "Default type"     0}                         Default type
 @{" Definition of a procedure with parameters " Link "Global and local variables"    62} Global and local variables
 @{" Dereferencing a pointer " Link "Extracting data (dereferencing pointers)"     0}              Extracting data (dereferencing pointers)
 @{" Derivation (OOP) " Link "Inheritance"     0}                     Inheritance
 @{" Derived class " Link "Inheritance"     0}                        Inheritance
 @{" Descoping a global variable " Link "Global and local variables"    57}          Global and local variables
 @{" Destructor " Link "Classes and methods"    20}                           Classes and methods
 @{" Destructor, end " Link "Methods in E"   118}                      Methods in E
 @{" Direct type " Link "Indirect types"    21}                          Indirect types
 @{" Division " Link "Mathematics"     0}                             Mathematics
 @{" Division, 32-bit " Link "Maths and logic functions"     0}                     Maths and logic functions
 @{" Double quote " Link "String Constants Special Character Sequences"     0}                         String Constants Special Character Sequences
 @{" Doubly linked list " Link "Linked Lists"    62}                   Linked Lists
 @{" Dragon curve " Link "Recursion Example"     0}                         Recursion Example
 @{" Drawing, box " Link "Graphics functions"    30}                         Graphics functions
 @{" Drawing, line " Link "Graphics functions"    27}                        Graphics functions
 @{" Drawing, text " Link "Graphics functions"    42}                        Graphics functions
 @{" Dynamic (typed) memory allocation " Link "NEW and END Operators"     0}    NEW and END Operators
 @{" Dynamic E-list allocation " Link "List functions"    12}            List functions
 @{" Dynamic E-string allocation " Link "String functions"    14}          String functions
 @{" Dynamic memory allocation " Link "Dynamic Allocation"     0}            Dynamic Allocation
 @{" Dynamic type " Link "Inheritance in E"   147}                         Inheritance in E
 @{" E author " Link "Amiga E Author"     0}                             Amiga E Author
 @{" E-list " Link "Lists and E-lists"     0}                               Lists and E-lists
 @{" E-list functions " Link "List functions"     0}                     List functions
 @{" E-list, append " Link "List functions"    47}                       List functions
 @{" E-list, comparison " Link "List functions"    28}                   List functions
 @{" E-list, copying " Link "List functions"    37}                      List functions
 @{" E-list, dynamic allocation " Link "List functions"    12}           List functions
 @{" E-list, length " Link "List functions"    55}                       List functions
 @{" E-list, maximum length " Link "List functions"    59}               List functions
 @{" E-list, setting the length " Link "List functions"    62}           List functions
 @{" E-string " Link "Normal strings and E-strings"    39}                             Normal strings and E-strings
 @{" E-string functions " Link "String functions"     0}                   String functions
 @{" E-string handling example " Link "String Handling and I-O"     0}            String Handling and I-O
 @{" E-string, append " Link "String functions"    96}                     String functions
 @{" E-string, comparison " Link "String functions"    37}                 String functions
 @{" E-string, copying " Link "String functions"    55}                    String functions
 @{" E-string, dynamic allocation " Link "String functions"    14}         String functions
 @{" E-string, format text to " Link "Input and output functions"    88}             Input and output functions
 @{" E-string, length " Link "String functions"   122}                     String functions
 @{" E-string, lowercase " Link "String functions"   166}                  String functions
 @{" E-string, maximum length " Link "String functions"   128}             String functions
 @{" E-string, middle copy " Link "String functions"   141}                String functions
 @{" E-string, reading from a file " Link "Input and output functions"   110}        Input and output functions
 @{" E-string, right-hand copy " Link "String functions"   133}            String functions
 @{" E-string, set length " Link "String functions"   175}                 String functions
 @{" E-string, trim leading whitespace " Link "String functions"   158}    String functions
 @{" E-string, uppercase " Link "String functions"   171}                  String functions
 @{" Early termination of a function " Link "Functions"    33}      Functions
 @{" ec compiler " Link "Compilation"     0}                          Compilation
 @{" Element selection " Link "Element selection and element types"     0}                    Element selection and element types
 @{" Element types " Link "Element selection and element types"    13}                        Element selection and element types
 @{" Elements of a linked list " Link "Linked Lists"    13}            Linked Lists
 @{" Elements of an array " Link "Accessing array data"     0}                 Accessing array data
 @{" Elements of an object " Link "OBJECT Type"     0}                OBJECT Type
 @{" Emodules: assignment " Link "Using Modules"     0}                 Using Modules
 @{" end destructor " Link "Methods in E"   118}                       Methods in E
 @{" End of file " Link "Input and output functions"   105}                          Input and output functions
 @{" Enumeration " Link "Enumerations"     0}                          Enumerations
 @{" EOF " Link "Input and output functions"   105}                                  Input and output functions
 @{" Error handling " Link "Exception Handling"     0}                       Exception Handling
 @{" Escape character " Link "String Constants Special Character Sequences"     0}                     String Constants Special Character Sequences
 @{" Evaluation of quoted expressions " Link "Evaluation"     0}     Evaluation
 @{" Even number " Link "Maths and logic functions"    40}                          Maths and logic functions
 @{" Example module use " Link "Example Module Use"     0}                   Example Module Use
 @{" Examples, altering " Link "Tinkering with the example"     0}                   Tinkering with the example
 @{" Examples, tinkering " Link "Tinkering with the example"     0}                  Tinkering with the example
 @{" Exception " Link "Exception Handling"     0}                            Exception Handling
 @{" Exception handler in a procedure " Link "Procedures with Exception Handlers"     0}     Procedures with Exception Handlers
 @{" Exception handling " Link "Exception Handling"     0}                   Exception Handling
 @{" Exception, automatic " Link "Automatic Exceptions"     0}                 Automatic Exceptions
 @{" Exception, raising " Link "Raising an Exception"     0}                   Raising an Exception
 @{" Exception, raising from a handler " Link "Raise within an Exception Handler"     0}    Raise within an Exception Handler
 @{" Exception, recursive handling " Link "Stack and Exceptions"     9}        Stack and Exceptions
 @{" Exception, throwing " Link "Raising an Exception"     0}                  Raising an Exception
 @{" Exception, use of stack " Link "Stack and Exceptions"     0}              Stack and Exceptions
 @{" Exception, zero " Link "Raising an Exception"    73}                      Raising an Exception
 @{" Exceptions and initialisation " Link "Raise within an Exception Handler"    54}        Raise within an Exception Handler
 @{" Exclusive or " Link "Maths and logic functions"    14}                         Maths and logic functions
 @{" Executing a procedure " Link "Procedure Execution"     0}                Procedure Execution
 @{" Execution " Link "Execution"     0}                            Execution
 @{" Execution, jumping to a label " Link "Labelling and the JUMP statement"     0}        Labelling and the JUMP statement
 @{" Exists a list element " Link "Lists and quoted expressions"    46}                Lists and quoted expressions
 @{" EXIT statement " Link "EXIT statement"     0}                       EXIT statement
 @{" Exiting a loop " Link "EXIT statement"     0}                       EXIT statement
 @{" Exponentiation " Link "Floating-Point Functions"    66}                       Floating-Point Functions
 @{" Expression " Link "Variables and Expressions"     0}                           Variables and Expressions
 @{" Expression " Link "Expressions"     0}                           Expressions
 @{" Expression in parentheses " Link "Precedence and grouping"     0}            Precedence and grouping
 @{" Expression, assignment " Link "Assignments"     0}               Assignments
 @{" Expression, bad grouping " Link "Precedence and grouping"    24}             Precedence and grouping
 @{" Expression, bracketing " Link "Precedence and grouping"     0}               Precedence and grouping
 @{" Expression, BUT " Link "BUT expression"     0}                      BUT expression
 @{" Expression, conversion to a statement " Link "Turning an Expression into a Statement"     0} Turning an Expression into a Statement
 @{" Expression, grouping " Link "Precedence and grouping"     0}                 Precedence and grouping
 @{" Expression, IF " Link "IF expression"     0}                       IF expression
 @{" Expression, quotable " Link "Quotable expressions"     0}                 Quotable expressions
 @{" Expression, quoted " Link "Quoted Expressions"     0}                   Quoted Expressions
 @{" Expression, sequence " Link "BUT expression"     0}                 BUT expression
 @{" Expression, side-effects " Link "Side-effects"     0}             Side-effects
 @{" Expression, timing example " Link "Timing Expressions"     0}           Timing Expressions
 @{" Expression, voiding " Link "Turning an Expression into a Statement"     0}                  Turning an Expression into a Statement
 @{" Extracting data from a pointer " Link "Extracting data (dereferencing pointers)"     0}       Extracting data (dereferencing pointers)
 @{" Extracting floating-point numbers from a string " Link "Floating-Point Functions"    10} Floating-Point Functions
 @{" Extracting numbers from a string " Link "String functions"   195}     String functions
 @{" Factorial function " Link "Factorial Example"     0}                   Factorial Example
 @{" Field formatting " Link "Input and output functions"    37}                     Input and output functions
 @{" Field size " Link "Input and output functions"    37}                           Input and output functions
 @{" Field, left-justify " Link "Input and output functions"    53}                  Input and output functions
 @{" Field, right-justify " Link "Input and output functions"    53}                 Input and output functions
 @{" Field, zero fill " Link "Input and output functions"    53}                     Input and output functions
 @{" File length " Link "Input and output functions"   150}                          Input and output functions
 @{" Filtering a list " Link "Lists and quoted expressions"    62}                     Lists and quoted expressions
 @{" Find sub-string in a string " Link "String functions"   153}          String functions
 @{" Finding addresses " Link "Finding addresses (making pointers)"     0}                    Finding addresses (making pointers)
 @{" Finding bugs " Link "Common Problems"     0}                         Common Problems
 @{" First element of an array " Link "Accessing array data"    55}            Accessing array data
 @{" Flag, AND-ing " Link "Sets"    19}                        Sets
 @{" Flag, IDCMP " Link "Intuition support functions"    70}                          Intuition support functions
 @{" Flag, mouse button " Link "Intuition support functions"   244}                   Intuition support functions
 @{" Flag, OR-ing " Link "Sets"    19}                         Sets
 @{" Flag, screen resolution " Link "Intuition support functions"   171}              Intuition support functions
 @{" Flag, set constant " Link "Sets"     0}                   Sets
 @{" Flag, window " Link "Intuition support functions"    89}                         Intuition support functions
 @{" Floating-point conversion operator " Link "Floating-Point Calculations"     0}   Floating-Point Calculations
 @{" Floating-point functions " Link "Floating-Point Functions"     0}             Floating-Point Functions
 @{" Floating-point number " Link "Floating-Point Numbers"     0}                Floating-Point Numbers
 @{" Floating-point number, extracting from a string " Link "Floating-Point Functions"    10} Floating-Point Functions
 @{" Floor of a floating-point value " Link "Floating-Point Functions"    59}      Floating-Point Functions
 @{" Flow control " Link "Program Flow Control"     0}                         Program Flow Control
 @{" Following elements in a linked list " Link "Linked Lists"    54}  Linked Lists
 @{" Font, setting Topaz " Link "Graphics functions"    66}                  Graphics functions
 @{" For all list elements " Link "Lists and quoted expressions"    29}                Lists and quoted expressions
 @{" FOR loop " Link "FOR loop"     0}                             FOR loop
 @{" Foreground pen, setting colour " Link "Graphics functions"    35}       Graphics functions
 @{" Format rules " Link "Format and Layout"     0}                         Format and Layout
 @{" Format text to an E-string " Link "Input and output functions"    88}           Input and output functions
 @{" Forward through a linked list " Link "Linked Lists"    54}        Linked Lists
 @{" Fragment, code " Link "Conditional Block"     0}                       Conditional Block
 @{" Free stack space " Link "System support functions"    78}                     System support functions
 @{" Freeing complex memory " Link "System support functions"    43}               System support functions
 @{" Freeing memory " Link "System support functions"    38}                       System support functions
 @{" Function " Link "Procedures and Functions"     0}                             Procedures and Functions
 @{" Function, built-in " Link "Built-In Functions"     0}                   Built-In Functions
 @{" Function, early termination " Link "Functions"    33}          Functions
 @{" Function, factorial " Link "Factorial Example"     0}                  Factorial Example
 @{" Function, graphics " Link "Graphics functions"     0}                   Graphics functions
 @{" Function, input " Link "Input and output functions"     0}                      Input and output functions
 @{" Function, Intuition support " Link "Intuition support functions"     0}          Intuition support functions
 @{" Function, logic " Link "Maths and logic functions"     0}                      Maths and logic functions
 @{" Function, maths " Link "Maths and logic functions"     0}                      Maths and logic functions
 @{" Function, one-line " Link "One-Line Functions"     0}                   One-Line Functions
 @{" Function, output " Link "Input and output functions"     0}                     Input and output functions
 @{" Function, recursive " Link "Recursion"     0}                  Recursion
 @{" Function, return value " Link "Functions"     0}               Functions
 @{" Function, system support " Link "System support functions"     0}             System support functions
 @{" Functions, floating-point " Link "Floating-Point Functions"     0}            Floating-Point Functions
 @{" Functions, linked list " Link "Linked Lists"    13}               Linked Lists
 @{" Functions, list and E-list " Link "List functions"     0}           List functions
 @{" Functions, string and E-string " Link "String functions"     0}       String functions
 @{" Further reading " Link "Further Reading"     0}                      Further Reading
 @{" Gadget and IDCMP example " Link "IDCMP Messages"     0}             IDCMP Messages
 @{" Gadget, create " Link "Intuition support functions"   187}                       Intuition support functions
 @{" Gadgets example " Link "Gadgets"     0}                      Gadgets
 @{" General loop " Link "LOOP block"     0}                         LOOP block
 @{" Global variable " Link "Global and local variables"     0}                      Global and local variables
 @{" Global variable, descoping " Link "Global and local variables"    57}           Global and local variables
 @{" Graphics example " Link "Graphics"     0}                     Graphics
 @{" Graphics functions " Link "Graphics functions"     0}                   Graphics functions
 @{" Grouping expressions " Link "Precedence and grouping"     0}                 Precedence and grouping
 @{" Grouping, bad " Link "Precedence and grouping"    24}                        Precedence and grouping
 @{" Guide author " Link "Guide Author"     0}                         Guide Author
 @{" Handler in a procedure " Link "Procedures with Exception Handlers"     0}               Procedures with Exception Handlers
 @{" Handler raising an exception " Link "Raise within an Exception Handler"     0}         Raise within an Exception Handler
 @{" Handler, recursive " Link "Stack and Exceptions"     9}                   Stack and Exceptions
 @{" Handling exceptions " Link "Exception Handling"     0}                  Exception Handling
 @{" Head of a linked list " Link "Linked Lists"    23}                Linked Lists
 @{" Header file, convert to module " Link "Non-Standard Modules"     0}       Non-Standard Modules
 @{" Hexadecimal constant " Link "Numeric Constants"     0}                 Numeric Constants
 @{" Hexadecimal number, printing " Link "Input and output functions"     0}         Input and output functions
 @{" Hierarchy, class " Link "Inheritance in E"   173}                     Inheritance in E
 @{" Horizontal FOR loop " Link "FOR loop"    55}                  FOR loop
 @{" Horizontal function definition " Link "One-Line Functions"     0}       One-Line Functions
 @{" Horizontal IF block " Link "IF block"    29}                  IF block
 @{" Horizontal WHILE loop " Link "WHILE loop"    57}                WHILE loop
 @{" I/O example " Link "String Handling and I-O"     0}                          String Handling and I-O
 @{" I/O example, with handler " Link "String Handling and I-O"   307}            String Handling and I-O
 @{" iaddr part of Intuition message " Link "Intuition support functions"   319}      Intuition support functions
 @{" IDCMP and gadget example " Link "IDCMP Messages"     0}             IDCMP Messages
 @{" IDCMP flags " Link "Intuition support functions"    70}                          Intuition support functions
 @{" IDCMP message, code part " Link "Intuition support functions"   316}             Intuition support functions
 @{" IDCMP message, iaddr part " Link "Intuition support functions"   319}            Intuition support functions
 @{" IDCMP message, qual part " Link "Intuition support functions"   324}             Intuition support functions
 @{" IDCMP message, waiting for " Link "Intuition support functions"   285}           Intuition support functions
 @{" Identifier " Link "Identifiers"     0}                           Identifiers
 @{" Identifier, case of characters " Link "Identifiers"     0}       Identifiers
 @{" IF block " Link "IF block"     0}                             IF block
 @{" IF block, nested " Link "IF block"    74}                     IF block
 @{" IF block, overlapping conditions " Link "IF block"    80}     IF block
 @{" IF expression " Link "IF expression"     0}                        IF expression
 @{" Illegal declaration " Link "Indirect types"     0}                  Indirect types
 @{" Include file, convert to module " Link "Non-Standard Modules"     0}      Non-Standard Modules
 @{" Incrementing a variable " Link "INC and DEC statements"     0}              INC and DEC statements
 @{" Incrementing array pointer " Link "Point to other elements"     0}           Point to other elements
 @{" Indentation " Link "Spacing and Separators"     0}                          Spacing and Separators
 @{" Indirect type " Link "Indirect types"     0}                        Indirect types
 @{" Inheritance (OOP) " Link "Inheritance"     0}                    Inheritance
 @{" Inheritance, OBJECT..OF " Link "Inheritance in E"     0}              Inheritance in E
 @{" Initialisation and automatic exceptions " Link "Raise within an Exception Handler"    54} Raise within an Exception Handler
 @{" Initialised array " Link "Typed lists"     0}                    Typed lists
 @{" Initialised declaration " Link "Initialised Declarations"     0}              Initialised Declarations
 @{" Inlining procedures " Link "Style Reuse and Readability"     0}                  Style Reuse and Readability
 @{" Input a character " Link "Input and output functions"   105}                    Input and output functions
 @{" Input a string " Link "Input and output functions"   110}                       Input and output functions
 @{" Input functions " Link "Input and output functions"     0}                      Input and output functions
 @{" Input/output example " Link "String Handling and I-O"     0}                 String Handling and I-O
 @{" Input/output example, with handler " Link "String Handling and I-O"   307}   String Handling and I-O
 @{" Interface " Link "Classes and methods"     0}                            Classes and methods
 @{" Intuition message flags " Link "Intuition support functions"    70}              Intuition support functions
 @{" Intuition message, code part " Link "Intuition support functions"   316}         Intuition support functions
 @{" Intuition message, iaddr part " Link "Intuition support functions"   319}        Intuition support functions
 @{" Intuition message, qual part " Link "Intuition support functions"   324}         Intuition support functions
 @{" Intuition message, waiting for " Link "Intuition support functions"   285}       Intuition support functions
 @{" Intuition support functions " Link "Intuition support functions"     0}          Intuition support functions
 @{" Iteration " Link "Loops"     0}                            Loops
 @{" Jumping out of a loop " Link "Labelling and the JUMP statement"    28}                Labelling and the JUMP statement
 @{" Jumping to a label " Link "Labelling and the JUMP statement"     0}                   Labelling and the JUMP statement
 @{" Kickstart version " Link "System support functions"    83}                    System support functions
 @{" Label " Link "Labelling and the JUMP statement"     0}                                Labelling and the JUMP statement
 @{" Label, use in Assembly " Link "Assembly and the E language"    28}               Assembly and the E language
 @{" Languages " Link "Introduction to Amiga E"     0}                            Introduction to Amiga E
 @{" Layout rules " Link "Format and Layout"     0}                         Format and Layout
 @{" Leaf " Link "Binary Trees"     0}                                 Binary Trees
 @{" Left mouse button click " Link "Intuition support functions"   276}              Intuition support functions
 @{" Left mouse button click (wait) " Link "Intuition support functions"   327}       Intuition support functions
 @{" Left shift " Link "Maths and logic functions"    99}                           Maths and logic functions
 @{" Left-hand side of an assignment, allowable " Link "Assignments"    33} Assignments
 @{" Left-justify field " Link "Input and output functions"    53}                   Input and output functions
 @{" Length (maximum) of an E-list " Link "List functions"    59}        List functions
 @{" Length (maximum) of an E-string " Link "String functions"   128}      String functions
 @{" Length of a file " Link "Input and output functions"   150}                     Input and output functions
 @{" Length of a list " Link "List functions"    55}                     List functions
 @{" Length of a string " Link "String functions"   105}                   String functions
 @{" Length of an E-list, setting " Link "List functions"    62}         List functions
 @{" Length of an E-string " Link "String functions"   122}                String functions
 @{" Length of an E-string, setting " Link "String functions"   175}       String functions
 @{" Line drawing " Link "Graphics functions"    27}                         Graphics functions
 @{" Linefeed " Link "String Constants Special Character Sequences"     0}                             String Constants Special Character Sequences
 @{" Linefeed problem " Link "Execution"    20}                     Execution
 @{" Linefeed problem, cure " Link "Strings"     0}               Strings
 @{" Linefeed, \n " Link "Strings"     0}                         Strings
 @{" Linked list " Link "Linked Lists"     0}                          Linked Lists
 @{" Linked list, doubly " Link "Linked Lists"    62}                  Linked Lists
 @{" Linked list, elements " Link "Linked Lists"    13}                Linked Lists
 @{" Linked list, following elements " Link "Linked Lists"    54}      Linked Lists
 @{" Linked list, functions " Link "Linked Lists"    13}               Linked Lists
 @{" Linked list, head " Link "Linked Lists"    23}                    Linked Lists
 @{" Linked list, linking " Link "Linked Lists"    23}                 Linked Lists
 @{" Linked list, next element " Link "Linked Lists"    36}            Linked Lists
 @{" Linked list, singly " Link "Linked Lists"    62}                  Linked Lists
 @{" Linking a linked list " Link "Linked Lists"    23}                Linked Lists
 @{" List " Link "Lists and E-lists"     0}                                 Lists and E-lists
 @{" List functions " Link "List functions"     0}                       List functions
 @{" List, append " Link "List functions"    47}                         List functions
 @{" List, comparison " Link "List functions"    28}                     List functions
 @{" List, copying " Link "List functions"    37}                        List functions
 @{" List, filtering " Link "Lists and quoted expressions"    62}                      Lists and quoted expressions
 @{" List, for all elements " Link "Lists and quoted expressions"    29}               Lists and quoted expressions
 @{" List, length " Link "List functions"    55}                         List functions
 @{" List, linked " Link "Linked Lists"     0}                         Linked Lists
 @{" List, mapping a quoted expression " Link "Lists and quoted expressions"     8}    Lists and quoted expressions
 @{" List, normal " Link "Lists and E-lists"     0}                         Lists and E-lists
 @{" List, selecting an element " Link "List functions"    65}           List functions
 @{" List, tag " Link "Lists and E-lists"    42}                            Lists and E-lists
 @{" List, there exists an element " Link "Lists and quoted expressions"    46}        Lists and quoted expressions
 @{" List, typed " Link "Typed lists"     0}                          Typed lists
 @{" Lists and quoted expressions " Link "Lists and quoted expressions"     0}         Lists and quoted expressions
 @{" Local variable " Link "Global and local variables"     0}                       Global and local variables
 @{" Local variable, same names " Link "Global and local variables"    32}           Global and local variables
 @{" Local variable, self " Link "Methods in E"    67}                 Methods in E
 @{" Local variables in a quoted expression " Link "Quotable expressions"     0} Quotable expressions
 @{" Locate sub-string in a string " Link "String functions"   153}        String functions
 @{" Location, memory " Link "Addresses"     0}                     Addresses
 @{" Location, memory " Link "Memory addresses"     0}                     Memory addresses
 @{" Logarithm, common " Link "Floating-Point Functions"    73}                    Floating-Point Functions
 @{" Logarithm, natural " Link "Floating-Point Functions"    73}                   Floating-Point Functions
 @{" Logic " Link "Logic and comparison"     0}                                Logic and comparison
 @{" Logic functions " Link "Maths and logic functions"     0}                      Maths and logic functions
 @{" Logic operators " Link "Logic and comparison"    11}                      Logic and comparison
 @{" Logic, and " Link "Maths and logic functions"    14}                           Maths and logic functions
 @{" Logic, exclusive or " Link "Maths and logic functions"    14}                  Maths and logic functions
 @{" Logic, not " Link "Maths and logic functions"    14}                           Maths and logic functions
 @{" Logic, or " Link "Maths and logic functions"    14}                            Maths and logic functions
 @{" LONG type " Link "LONG Type"     0}                            LONG Type
 @{" LONG type, definition " Link "Indirect types"    21}                Indirect types
 @{" Loop " Link "Loops"     0}                                 Loops
 @{" LOOP block " Link "LOOP block"     0}                           LOOP block
 @{" Loop check, REPEAT..UNTIL " Link "REPEAT..UNTIL loop"    18}            REPEAT..UNTIL loop
 @{" Loop check, WHILE " Link "WHILE loop"    22}                    WHILE loop
 @{" Loop termination " Link "WHILE loop"    61}                     WHILE loop
 @{" Loop, EXIT " Link "EXIT statement"     0}                           EXIT statement
 @{" Loop, exiting " Link "EXIT statement"     0}                        EXIT statement
 @{" Loop, FOR " Link "FOR loop"     0}                            FOR loop
 @{" Loop, general " Link "LOOP block"     0}                        LOOP block
 @{" Loop, LOOP " Link "LOOP block"     0}                           LOOP block
 @{" Loop, REPEAT..UNTIL " Link "REPEAT..UNTIL loop"     0}                  REPEAT..UNTIL loop
 @{" Loop, terminate by jumping to a label " Link "Labelling and the JUMP statement"    28} Labelling and the JUMP statement
 @{" Loop, WHILE " Link "WHILE loop"     0}                          WHILE loop
 @{" Lowercase a string " Link "String functions"   166}                   String functions
 @{" main procedure " Link "Procedures"     0}                       Procedures
 @{" Making pointers " Link "Finding addresses (making pointers)"     0}                      Finding addresses (making pointers)
 @{" Manipulation, safe " Link "LIST and STRING Types"     0}                   LIST and STRING Types
 @{" Mapping a quoted expression over a list " Link "Lists and quoted expressions"     8} Lists and quoted expressions
 @{" Matching patterns " Link "Unification"     0}                    Unification
 @{" Mathematical operators " Link "Mathematics"     0}               Mathematics
 @{" Maths functions " Link "Maths and logic functions"     0}                      Maths and logic functions
 @{" Maximum " Link "Maths and logic functions"    48}                              Maths and logic functions
 @{" Maximum length of an E-list " Link "List functions"    59}          List functions
 @{" Maximum length of an E-string " Link "String functions"   128}        String functions
 @{" Memory address " Link "Addresses"     0}                       Addresses
 @{" Memory address " Link "Memory addresses"     0}                       Memory addresses
 @{" Memory, allocating " Link "System support functions"     0}                   System support functions
 @{" Memory, allocation " Link "Memory Allocation"     0}                   Memory Allocation
 @{" Memory, deallocate " Link "System support functions"    38}                   System support functions
 @{" Memory, deallocate complex " Link "System support functions"    43}           System support functions
 @{" Memory, deallocation " Link "Deallocation of Memory"     0}                 Deallocation of Memory
 @{" Memory, dynamic (typed) allocation " Link "NEW and END Operators"     0}   NEW and END Operators
 @{" Memory, dynamic allocation " Link "Dynamic Allocation"     0}           Dynamic Allocation
 @{" Memory, free " Link "System support functions"    38}                         System support functions
 @{" Memory, free complex " Link "System support functions"    43}                 System support functions
 @{" Memory, reading " Link "Maths and logic functions"   114}                      Maths and logic functions
 @{" Memory, sharing " Link "Assignment and Copying"    40}                      Assignment and Copying
 @{" Memory, static allocation " Link "Static Allocation"     0}            Static Allocation
 @{" Memory, writing " Link "Maths and logic functions"   121}                      Maths and logic functions
 @{" Method (OOP) " Link "Classes and methods"     0}                         Classes and methods
 @{" Method, abstract " Link "Inheritance in E"   275}                     Inheritance in E
 @{" Method, calling " Link "Methods in E"    28}                      Methods in E
 @{" Method, constructor " Link "Classes and methods"    20}                  Classes and methods
 @{" Method, destructor " Link "Classes and methods"    20}                   Classes and methods
 @{" Method, end " Link "Methods in E"   118}                          Methods in E
 @{" Method, overriding " Link "Inheritance in E"    96}                   Inheritance in E
 @{" Method, PROC..OF " Link "Methods in E"     0}                     Methods in E
 @{" Method, self local variable " Link "Methods in E"    67}          Methods in E
 @{" Middle copy of a string " Link "String functions"   141}              String functions
 @{" Minimum " Link "Maths and logic functions"    51}                              Maths and logic functions
 @{" Mnemonics, Assembly " Link "Assembly Statements"     0}                  Assembly Statements
 @{" Module " Link "Modules"     0}                               Modules
 @{" Module, Amiga system " Link "Amiga System Modules"     0}                 Amiga System Modules
 @{" Module, code " Link "Code Modules"     0}                         Code Modules
 @{" Module, convert from include, header or pragma file " Link "Non-Standard Modules"     0} Non-Standard Modules
 @{" Module, example use " Link "Example Module Use"     0}                  Example Module Use
 @{" Module, non-standard " Link "Non-Standard Modules"     0}                 Non-Standard Modules
 @{" Module, using " Link "Using Modules"     0}                        Using Modules
 @{" Module, view contents " Link "Using Modules"    18}                Using Modules
 @{" Modules and classes " Link "Data-Hiding in E"     0}                  Data-Hiding in E
 @{" Modulus " Link "Maths and logic functions"    69}                              Maths and logic functions
 @{" Mouse button flags " Link "Intuition support functions"   244}                   Intuition support functions
 @{" Mouse buttons state " Link "Intuition support functions"   235}                  Intuition support functions
 @{" Mouse click, left button " Link "Intuition support functions"   276}             Intuition support functions
 @{" Mouse click, left button (wait) " Link "Intuition support functions"   327}      Intuition support functions
 @{" Mouse x-coordinate " Link "Intuition support functions"   256}                   Intuition support functions
 @{" Mouse y-coordinate " Link "Intuition support functions"   266}                   Intuition support functions
 @{" Multiple return values " Link "Multiple Return Values"     0}               Multiple Return Values
 @{" Multiple-assignment " Link "Multiple Return Values"    12}                  Multiple Return Values
 @{" Multiplication " Link "Mathematics"     0}                       Mathematics
 @{" Multiplication, 32-bit " Link "Maths and logic functions"     0}               Maths and logic functions
 @{" Mutual recursion " Link "Mutual Recursion"     0}                     Mutual Recursion
 @{" Named constant " Link "Named Constants"     0}                       Named Constants
 @{" Named data " Link "Variables and Expressions"     0}                           Variables and Expressions
 @{" Named elements " Link "OBJECT Type"     0}                       OBJECT Type
 @{" Names of constructors " Link "Methods in E"    78}                Methods in E
 @{" Names of local variables " Link "Global and local variables"    32}             Global and local variables
 @{" Natural logarithm " Link "Floating-Point Functions"    73}                    Floating-Point Functions
 @{" Nested comment " Link "Comments"     7}                       Comments
 @{" Nested IF blocks " Link "IF block"    74}                     IF block
 @{" Next element of a linked list " Link "Linked Lists"    36}        Linked Lists
 @{" Node " Link "Binary Trees"     0}                                 Binary Trees
 @{" Non-standard module " Link "Non-Standard Modules"     0}                  Non-Standard Modules
 @{" Normal list " Link "Lists and E-lists"     0}                          Lists and E-lists
 @{" Normal list, selecting an element " Link "List functions"    65}    List functions
 @{" Normal string " Link "Normal strings and E-strings"     0}                        Normal strings and E-strings
 @{" Not " Link "Maths and logic functions"    14}                                  Maths and logic functions
 @{" Null character " Link "String Constants Special Character Sequences"     0}                       String Constants Special Character Sequences
 @{" Number, even " Link "Maths and logic functions"    40}                         Maths and logic functions
 @{" Number, extracting from a string " Link "String functions"   195}     String functions
 @{" Number, floating-point " Link "Floating-Point Numbers"     0}               Floating-Point Numbers
 @{" Number, odd " Link "Maths and logic functions"    44}                          Maths and logic functions
 @{" Number, printing " Link "Input and output functions"     0}                     Input and output functions
 @{" Number, printing (simple) " Link "Changing the example"    17}            Changing the example
 @{" Number, quick random " Link "Maths and logic functions"    92}                 Maths and logic functions
 @{" Number, random " Link "Maths and logic functions"    83}                       Maths and logic functions
 @{" Number, real " Link "Floating-Point Numbers"     0}                         Floating-Point Numbers
 @{" Number, signed or unsigned " Link "Signed and Unsigned Values"     0}           Signed and Unsigned Values
 @{" Numbered elements of an array " Link "Accessing array data"     0}        Accessing array data
 @{" Numeric constant " Link "Numeric Constants"     0}                     Numeric Constants
 @{" Object " Link "OBJECT Type"     0}                               OBJECT Type
 @{" Object (OOP) " Link "Classes and methods"     0}                         Classes and methods
 @{" Object element types " Link "Element selection and element types"    13}                 Element selection and element types
 @{" Object elements, private " Link "Data-Hiding in E"     0}             Data-Hiding in E
 @{" Object elements, public " Link "Data-Hiding in E"     0}              Data-Hiding in E
 @{" Object pointer " Link "Element selection and element types"     8}                       Element selection and element types
 @{" Object selection, use of ++ and - " Link "Element selection and element types"    44}    Element selection and element types
 @{" Object, allocation " Link "Objects in E"    17}                   Objects in E
 @{" Object, Amiga system " Link "Amiga system objects"     0}                 Amiga system objects
 @{" Object, deallocation " Link "Objects in E"    31}                 Objects in E
 @{" Object, element selection " Link "Element selection and element types"     0}            Element selection and element types
 @{" Object, named elements " Link "OBJECT Type"     0}               OBJECT Type
 @{" Object, size " Link "SIZEOF expression"     0}                         SIZEOF expression
 @{" OBJECT..OF, inheritance " Link "Inheritance in E"     0}              Inheritance in E
 @{" Odd number " Link "Maths and logic functions"    44}                           Maths and logic functions
 @{" One-line function " Link "One-Line Functions"     0}                    One-Line Functions
 @{" OOP, class " Link "Classes and methods"     0}                           Classes and methods
 @{" OOP, derivation " Link "Inheritance"     0}                      Inheritance
 @{" OOP, inheritance " Link "Inheritance"     0}                     Inheritance
 @{" OOP, method " Link "Classes and methods"     0}                          Classes and methods
 @{" OOP, object " Link "Classes and methods"     0}                          Classes and methods
 @{" Open screen " Link "Intuition support functions"   129}                          Intuition support functions
 @{" Open window " Link "Intuition support functions"    16}                          Intuition support functions
 @{" Operator precedence " Link "Precedence and grouping"     0}                  Precedence and grouping
 @{" Operator, SUPER " Link "Inheritance in E"   110}                      Inheritance in E
 @{" Operators, comparison " Link "Logic and comparison"    11}                Logic and comparison
 @{" Operators, logic " Link "Logic and comparison"    11}                     Logic and comparison
 @{" Operators, mathematical " Link "Mathematics"     0}              Mathematics
 @{" Option, set constant " Link "Sets"     0}                 Sets
 @{" Optional return values " Link "Multiple Return Values"    32}               Multiple Return Values
 @{" Or " Link "Maths and logic functions"    14}                                   Maths and logic functions
 @{" OR, bit-wise " Link "Bitwise AND and OR"     0}                         Bitwise AND and OR
 @{" Or, exclusive " Link "Maths and logic functions"    14}                        Maths and logic functions
 @{" OR-ing flags " Link "Sets"    19}                         Sets
 @{" Output a character " Link "Input and output functions"    97}                   Input and output functions
 @{" Output functions " Link "Input and output functions"     0}                     Input and output functions
 @{" Output text " Link "Input and output functions"     0}                          Input and output functions
 @{" Output window " Link "Built-In Variables"    34}                        Built-In Variables
 @{" Overlapping conditions " Link "IF block"    80}               IF block
 @{" Overriding methods " Link "Inheritance in E"    96}                   Inheritance in E
 @{" Pad byte " Link "SIZEOF expression"    17}                             SIZEOF expression
 @{" Parameter " Link "Parameters"     0}                            Parameters
 @{" Parameter variable " Link "Global and local variables"     0}                   Global and local variables
 @{" Parameter, default " Link "Default Arguments"     0}                   Default Arguments
 @{" Parameter, procedure local variables " Link "Global and local variables"    62} Global and local variables
 @{" Parentheses and expressions " Link "Precedence and grouping"     0}          Precedence and grouping
 @{" Parsing command line arguments " Link "Argument Parsing"     0}       Argument Parsing
 @{" Pattern matching " Link "Unification"     0}                     Unification
 @{" Peeking memory " Link "Maths and logic functions"   114}                       Maths and logic functions
 @{" Pen colour, setting " Link "Graphics functions"    48}                  Graphics functions
 @{" Pen, setting foreground and background colour " Link "Graphics functions"    35} Graphics functions
 @{" Place-holder, decimal \d " Link "Changing the example"    17}             Changing the example
 @{" Place-holder, field formatting " Link "Input and output functions"    37}       Input and output functions
 @{" Place-holder, field size " Link "Input and output functions"    37}             Input and output functions
 @{" Place-holders " Link "Input and output functions"     0}                        Input and output functions
 @{" Plot a point " Link "Graphics functions"    16}                         Graphics functions
 @{" Point, plot " Link "Graphics functions"    16}                          Graphics functions
 @{" Pointer " Link "PTR Type"     0}                              PTR Type
 @{" Pointer (array) and array declaration " Link "Array pointers"    46} Array pointers
 @{" Pointer analogy " Link "Addresses"     0}                      Addresses
 @{" Pointer diagram " Link "Addresses"    29}                      Addresses
 @{" Pointer type " Link "PTR Type"     0}                         PTR Type
 @{" Pointer, array " Link "Array pointers"     0}                       Array pointers
 @{" Pointer, common use " Link "Extracting data (dereferencing pointers)"    89}                  Extracting data (dereferencing pointers)
 @{" Pointer, dereference " Link "Extracting data (dereferencing pointers)"     0}                 Extracting data (dereferencing pointers)
 @{" Pointer, making " Link "Finding addresses (making pointers)"     0}                      Finding addresses (making pointers)
 @{" Pointer, object " Link "Element selection and element types"     8}                      Element selection and element types
 @{" Pointer, sharing memory " Link "Assignment and Copying"    40}              Assignment and Copying
 @{" Poking memory " Link "Maths and logic functions"   121}                        Maths and logic functions
 @{" Polymorphism " Link "Inheritance in E"   147}                         Inheritance in E
 @{" Potential problems using Assembly " Link "Things to watch out for"     0}    Things to watch out for
 @{" Pragma file, convert to module " Link "Non-Standard Modules"     0}       Non-Standard Modules
 @{" Precedence, operators " Link "Precedence and grouping"     0}                Precedence and grouping
 @{" Printing characters " Link "Input and output functions"     0}                  Input and output functions
 @{" Printing decimal numbers " Link "Input and output functions"     0}             Input and output functions
 @{" Printing hexadecimal numbers " Link "Input and output functions"     0}         Input and output functions
 @{" Printing numbers " Link "Changing the example"    17}                     Changing the example
 @{" Printing strings " Link "Input and output functions"     0}                     Input and output functions
 @{" Printing text " Link "Input and output functions"     0}                        Input and output functions
 @{" Printing to an E-string " Link "Input and output functions"    88}              Input and output functions
 @{" Private, object elements " Link "Data-Hiding in E"     0}             Data-Hiding in E
 @{" Problems, common " Link "Common Problems"     0}                     Common Problems
 @{" PROC..OF, method " Link "Methods in E"     0}                     Methods in E
 @{" Procedure " Link "Procedures"     0}                            Procedures
 @{" Procedure argument " Link "Parameters"     0}                   Parameters
 @{" Procedure parameter " Link "Parameters"     0}                  Parameters
 @{" Procedure parameter local variables " Link "Global and local variables"    62}  Global and local variables
 @{" Procedure parameter types " Link "Procedure parameters"     0}            Procedure parameters
 @{" Procedure parameter variable " Link "Global and local variables"     0}         Global and local variables
 @{" Procedure parameter, array " Link "Array procedure parameters"     0}           Array procedure parameters
 @{" Procedure parameter, default " Link "Default Arguments"     0}         Default Arguments
 @{" Procedure with parameters, definition " Link "Global and local variables"    62} Global and local variables
 @{" Procedure, calling " Link "Procedure Execution"     0}                   Procedure Execution
 @{" Procedure, calling " Link "Procedures"     0}                   Procedures
 @{" Procedure, definition " Link "Procedure Definition"     0}                Procedure Definition
 @{" Procedure, early termination " Link "Functions"    33}         Functions
 @{" Procedure, exception handler " Link "Procedures with Exception Handlers"     0}         Procedures with Exception Handlers
 @{" Procedure, execution " Link "Procedure Execution"     0}                 Procedure Execution
 @{" Procedure, inlining " Link "Style Reuse and Readability"     0}                  Style Reuse and Readability
 @{" Procedure, recent " Link "Raising an Exception"    87}                    Raising an Exception
 @{" Procedure, return value " Link "Functions"     0}              Functions
 @{" Procedure, reuse " Link "Style Reuse and Readability"     0}                     Style Reuse and Readability
 @{" Procedure, running " Link "Procedures"     0}                   Procedures
 @{" Procedure, running " Link "Procedure Execution"     0}                   Procedure Execution
 @{" Procedure, style " Link "Style Reuse and Readability"     0}                     Style Reuse and Readability
 @{" Procedure, use in Assembly " Link "Assembly and the E language"    28}           Assembly and the E language
 @{" Program flow control " Link "Program Flow Control"     0}                 Program Flow Control
 @{" Program termination " Link "System support functions"    64}                  System support functions
 @{" Program, finish " Link "Procedures"     0}                      Procedures
 @{" Program, running " Link "Execution"     0}                     Execution
 @{" Program, start " Link "Procedures"     0}                       Procedures
 @{" Pseudo-random number " Link "Maths and logic functions"    83}                 Maths and logic functions
 @{" Public, object elements " Link "Data-Hiding in E"     0}              Data-Hiding in E
 @{" qual part of Intuition message " Link "Intuition support functions"   324}       Intuition support functions
 @{" Quick random number " Link "Maths and logic functions"    92}                  Maths and logic functions
 @{" Quotable expressions " Link "Quotable expressions"     0}                 Quotable expressions
 @{" Quoted expression " Link "Quoted Expressions"     0}                    Quoted Expressions
 @{" Quoted expression, evaluation " Link "Evaluation"     0}        Evaluation
 @{" Quoted expression, for all list elements " Link "Lists and quoted expressions"    29} Lists and quoted expressions
 @{" Quoted expression, local variables " Link "Quotable expressions"     0}   Quotable expressions
 @{" Quoted expression, mapping over a list " Link "Lists and quoted expressions"     8} Lists and quoted expressions
 @{" Quoted expression, there exists a list element " Link "Lists and quoted expressions"    46} Lists and quoted expressions
 @{" Quoted expressions and lists " Link "Lists and quoted expressions"     0}         Lists and quoted expressions
 @{" Raising an exception " Link "Raising an Exception"     0}                 Raising an Exception
 @{" Raising an exception from a handler " Link "Raise within an Exception Handler"     0}  Raise within an Exception Handler
 @{" Raising to a power " Link "Floating-Point Functions"    66}                   Floating-Point Functions
 @{" Random number " Link "Maths and logic functions"    83}                        Maths and logic functions
 @{" Random number, quick " Link "Maths and logic functions"    92}                 Maths and logic functions
 @{" Range of floating-point numbers " Link "Accuracy and Range"     0}      Accuracy and Range
 @{" ReadArgs, using " Link "AmigaDOS 2.0 (and above)"     0}                      AmigaDOS 2.0 (and above)
 @{" Reading a character from a file " Link "Input and output functions"   105}      Input and output functions
 @{" Reading a string from a file " Link "Input and output functions"   110}         Input and output functions
 @{" Reading from memory " Link "Maths and logic functions"   114}                  Maths and logic functions
 @{" Reading, further " Link "Further Reading"     0}                     Further Reading
 @{" Real number " Link "Floating-Point Numbers"     0}                          Floating-Point Numbers
 @{" Recent procedure " Link "Raising an Exception"    87}                     Raising an Exception
 @{" Recursion " Link "Recursion"     0}                            Recursion
 @{" Recursion example " Link "Recursion Example"     0}                    Recursion Example
 @{" Recursion, mutual " Link "Mutual Recursion"     0}                    Mutual Recursion
 @{" Recursive case " Link "Factorial Example"    44}                       Factorial Example
 @{" Recursive exception handling " Link "Stack and Exceptions"     9}         Stack and Exceptions
 @{" Recursive function " Link "Recursion"     0}                   Recursion
 @{" Recursive type " Link "Recursion"     0}                       Recursion
 @{" Registers, A4 and A5 " Link "Things to watch out for"    11}                 Things to watch out for
 @{" Regular return value " Link "Multiple Return Values"    32}                 Multiple Return Values
 @{" Remainder " Link "Maths and logic functions"    69}                            Maths and logic functions
 @{" REPEAT..UNTIL loop " Link "REPEAT..UNTIL loop"     0}                   REPEAT..UNTIL loop
 @{" REPEAT..UNTIL loop check " Link "REPEAT..UNTIL loop"    18}             REPEAT..UNTIL loop
 @{" REPEAT..UNTIL loop version of a FOR loop " Link "REPEAT..UNTIL loop"    17} REPEAT..UNTIL loop
 @{" Repeated execution " Link "Loops"     0}                   Loops
 @{" Resolution flags " Link "Intuition support functions"   171}                     Intuition support functions
 @{" Return value of a function " Link "Functions"     0}           Functions
 @{" Return value, optional " Link "Multiple Return Values"    32}               Multiple Return Values
 @{" Return value, regular " Link "Multiple Return Values"    32}                Multiple Return Values
 @{" Return values, multiple " Link "Multiple Return Values"     0}              Multiple Return Values
 @{" Reusing code " Link "Style Reuse and Readability"     0}                         Style Reuse and Readability
 @{" Reusing procedures " Link "Style Reuse and Readability"     0}                   Style Reuse and Readability
 @{" Revision, Kickstart " Link "System support functions"    83}                  System support functions
 @{" Rewriting a FOR loop as a REPEAT..UNTIL loop " Link "REPEAT..UNTIL loop"    17} REPEAT..UNTIL loop
 @{" Rewriting a FOR loop as a WHILE loop " Link "WHILE loop"    17} WHILE loop
 @{" Rewriting SELECT block as IF block " Link "SELECT block"    23}   SELECT block
 @{" Rewriting SELECT..OF block as IF block " Link "SELECT..OF block"    71} SELECT..OF block
 @{" Right shift " Link "Maths and logic functions"   107}                          Maths and logic functions
 @{" Right-hand copy of an E-string " Link "String functions"   133}       String functions
 @{" Right-justify field " Link "Input and output functions"    53}                  Input and output functions
 @{" Root " Link "Binary Trees"     0}                                 Binary Trees
 @{" Rounding a floating-point value " Link "Floating-Point Functions"    59}      Floating-Point Functions
 @{" Rules, format and layout " Link "Format and Layout"     0}             Format and Layout
 @{" Running a method " Link "Methods in E"    28}                     Methods in E
 @{" Running a procedure " Link "Procedures"     0}                  Procedures
 @{" Running a program " Link "Execution"     0}                    Execution
 @{" Safe manipulation " Link "LIST and STRING Types"     0}                    LIST and STRING Types
 @{" Same names of local variables " Link "Global and local variables"    32}        Global and local variables
 @{" Screen example, with handler " Link "Screens"    71}         Screens
 @{" Screen example, without handler " Link "Screens"     0}      Screens
 @{" Screen resolution flags " Link "Intuition support functions"   171}              Intuition support functions
 @{" Screen, close " Link "Intuition support functions"   178}                        Intuition support functions
 @{" Screen, open " Link "Intuition support functions"   129}                         Intuition support functions
 @{" Seed of a random sequence " Link "Maths and logic functions"    92}            Maths and logic functions
 @{" SELECT block " Link "SELECT block"     0}                         SELECT block
 @{" SELECT block, rewriting as IF block " Link "SELECT block"    23}  SELECT block
 @{" SELECT..OF block " Link "SELECT..OF block"     0}                     SELECT..OF block
 @{" SELECT..OF block, rewriting as IF block " Link "SELECT..OF block"    71} SELECT..OF block
 @{" SELECT..OF block, speed versus size " Link "SELECT..OF block"    90}  SELECT..OF block
 @{" Selecting an element of a normal list " Link "List functions"    65} List functions
 @{" Selecting an element of an object " Link "Element selection and element types"     0}    Element selection and element types
 @{" Selection, use of ++ and - " Link "Element selection and element types"    44}           Element selection and element types
 @{" self, method local variable " Link "Methods in E"    67}          Methods in E
 @{" Separators " Link "Spacing and Separators"     0}                           Spacing and Separators
 @{" Sequencing expressions " Link "BUT expression"     0}               BUT expression
 @{" Sequential composition " Link "Statements"    17}               Statements
 @{" Set " Link "Sets"     0}                                  Sets
 @{" Set length of an E-string " Link "String functions"   175}            String functions
 @{" Setting foreground and background pen colours " Link "Graphics functions"    35} Graphics functions
 @{" Setting pen colours " Link "Graphics functions"    48}                  Graphics functions
 @{" Setting stdin " Link "Input and output functions"   157}                        Input and output functions
 @{" Setting stdout " Link "Input and output functions"   166}                       Input and output functions
 @{" Setting stdrast " Link "Graphics functions"    57}                      Graphics functions
 @{" Setting the length of an E-list " Link "List functions"    62}      List functions
 @{" Setting Topaz font " Link "Graphics functions"    66}                   Graphics functions
 @{" Sharing memory " Link "Assignment and Copying"    40}                       Assignment and Copying
 @{" Shift left " Link "Maths and logic functions"    99}                           Maths and logic functions
 @{" Shift right " Link "Maths and logic functions"   107}                          Maths and logic functions
 @{" Short-hand for first element of an array " Link "Accessing array data"    55} Accessing array data
 @{" Show module contents " Link "Using Modules"    18}                 Using Modules
 @{" Side-effects " Link "Side-effects"     0}                         Side-effects
 @{" Sign of a number " Link "Maths and logic functions"    35}                     Maths and logic functions
 @{" Signed and unsigned values " Link "Signed and Unsigned Values"     0}           Signed and Unsigned Values
 @{" Sine function " Link "Floating-Point Functions"    51}                        Floating-Point Functions
 @{" Singly linked list " Link "Linked Lists"    62}                   Linked Lists
 @{" Size of an array " Link "Tables of data"     0}                     Tables of data
 @{" Size of an object " Link "SIZEOF expression"     0}                    SIZEOF expression
 @{" Size versus speed, SELECT..OF block " Link "SELECT..OF block"    90}  SELECT..OF block
 @{" Spacing " Link "Spacing and Separators"     0}                              Spacing and Separators
 @{" Special character sequences " Link "String Constants Special Character Sequences"     0}          String Constants Special Character Sequences
 @{" Speed versus size, SELECT..OF block " Link "SELECT..OF block"    90}  SELECT..OF block
 @{" Splitting a string over several lines " Link "Statements"    57} Statements
 @{" Splitting statements over several lines " Link "Statements"    29} Statements
 @{" Square root " Link "Floating-Point Functions"    63}                          Floating-Point Functions
 @{" Stack and crashing " Link "Stack (and Crashing)"     0}                   Stack (and Crashing)
 @{" Stack and exceptions " Link "Stack and Exceptions"     0}                 Stack and Exceptions
 @{" Stack space, free " Link "System support functions"    78}                    System support functions
 @{" Stack, avoiding crashes " Link "Stack (and Crashing)"    21}              Stack (and Crashing)
 @{" State of mouse buttons " Link "Intuition support functions"   235}               Intuition support functions
 @{" Statement " Link "Statements"     0}                            Statements
 @{" Statement, Assembly " Link "Assembly Statements"     0}                  Assembly Statements
 @{" Statement, breaking " Link "Statements"    29}                  Statements
 @{" Statement, conversion from an expression " Link "Turning an Expression into a Statement"     0} Turning an Expression into a Statement
 @{" Statement, several on one line " Link "Statements"    17}       Statements
 @{" Statement, splitting " Link "Statements"    29}                 Statements
 @{" Static data " Link "Static data"     0}                          Static data
 @{" Static data, potential problems " Link "Static data"    22}      Static data
 @{" Static memory allocation " Link "Static Allocation"     0}             Static Allocation
 @{" Static memory, use in Assembly " Link "Static memory"     0}       Static memory
 @{" stdin, setting " Link "Input and output functions"   157}                       Input and output functions
 @{" stdout, setting " Link "Input and output functions"   166}                      Input and output functions
 @{" stdrast, setting " Link "Graphics functions"    57}                     Graphics functions
 @{" String " Link "Normal strings and E-strings"     0}                               Normal strings and E-strings
 @{" String " Link "Strings"     0}                               Strings
 @{" String diagram " Link "Normal strings and E-strings"    38}                       Normal strings and E-strings
 @{" String functions " Link "String functions"     0}                     String functions
 @{" String handling example " Link "String Handling and I-O"     0}              String Handling and I-O
 @{" String handling example, with handler " Link "String Handling and I-O"   307} String Handling and I-O
 @{" STRING type " Link "Normal strings and E-strings"    49}                          Normal strings and E-strings
 @{" String, append " Link "String functions"    96}                       String functions
 @{" String, breaking " Link "Statements"    57}                     Statements
 @{" String, comparison " Link "String functions"    37}                   String functions
 @{" String, constant " Link "Normal strings and E-strings"     0}                     Normal strings and E-strings
 @{" String, converting to floating-point number " Link "Floating-Point Functions"    10} Floating-Point Functions
 @{" String, converting to numbers " Link "String functions"   195}        String functions
 @{" String, copying " Link "String functions"    55}                      String functions
 @{" String, find sub-string " Link "String functions"   153}              String functions
 @{" String, length " Link "String functions"   105}                       String functions
 @{" String, lowercase " Link "String functions"   166}                    String functions
 @{" String, middle copy " Link "String functions"   141}                  String functions
 @{" String, printing " Link "Input and output functions"     0}                     Input and output functions
 @{" String, right-hand copy " Link "String functions"   133}              String functions
 @{" String, special character sequence " Link "String Constants Special Character Sequences"     0}   String Constants Special Character Sequences
 @{" String, splitting " Link "Statements"    57}                    Statements
 @{" String, trim leading whitespace " Link "String functions"   158}      String functions
 @{" String, uppercase " Link "String functions"   171}                    String functions
 @{" Structure " Link "OBJECT Type"     0}                            OBJECT Type
 @{" Sub-string location in a string " Link "String functions"   153}      String functions
 @{" Subtraction " Link "Mathematics"     0}                          Mathematics
 @{" Successful, zero exception " Link "Raising an Exception"    73}           Raising an Exception
 @{" Summary of Part One " Link "Summary"     0}                  Summary
 @{" Super class " Link "Inheritance in E"   161}                          Inheritance in E
 @{" SUPER, operator " Link "Inheritance in E"   110}                      Inheritance in E
 @{" System function, calling from Assembly " Link "Assembly and the E language"    39} Assembly and the E language
 @{" System module " Link "Amiga System Modules"     0}                        Amiga System Modules
 @{" System objects " Link "Amiga system objects"     0}                       Amiga system objects
 @{" System support functions " Link "System support functions"     0}             System support functions
 @{" System variables " Link "Built-In Variables"     0}                     Built-In Variables
 @{" Tab character " Link "String Constants Special Character Sequences"     0}                        String Constants Special Character Sequences
 @{" Table of data " Link "Tables of data"     0}                        Tables of data
 @{" Tag list " Link "Lists and E-lists"    42}                             Lists and E-lists
 @{" Tail of a linked list " Link "Linked Lists"    23}                Linked Lists
 @{" Tangent function " Link "Floating-Point Functions"    51}                     Floating-Point Functions
 @{" Terminating loops " Link "WHILE loop"    61}                    WHILE loop
 @{" Termination, program " Link "System support functions"    64}                 System support functions
 @{" Test for control-C " Link "System support functions"    73}                   System support functions
 @{" Test for even number " Link "Maths and logic functions"    40}                 Maths and logic functions
 @{" Test for odd number " Link "Maths and logic functions"    44}                  Maths and logic functions
 @{" Text drawing " Link "Graphics functions"    42}                         Graphics functions
 @{" Text, printing " Link "Input and output functions"     0}                       Input and output functions
 @{" There exists a list element " Link "Lists and quoted expressions"    46}          Lists and quoted expressions
 @{" Throwing an exception " Link "Raising an Exception"     0}                Raising an Exception
 @{" Timing expressions example " Link "Timing Expressions"     0}           Timing Expressions
 @{" Tinkering " Link "Tinkering with the example"     0}                            Tinkering with the example
 @{" Topaz, setting font " Link "Graphics functions"    66}                  Graphics functions
 @{" Tree, binary " Link "Binary Trees"     0}                         Binary Trees
 @{" Tree, branch " Link "Binary Trees"     0}                         Binary Trees
 @{" Tree, leaf " Link "Binary Trees"     0}                           Binary Trees
 @{" Tree, node " Link "Binary Trees"     0}                           Binary Trees
 @{" Tree, root " Link "Binary Trees"     0}                           Binary Trees
 @{" Trigonometry functions " Link "Floating-Point Functions"    51}               Floating-Point Functions
 @{" Trim leading whitespace from a string " Link "String functions"   158} String functions
 @{" Trouble-shooting " Link "Common Problems"     0}                     Common Problems
 @{" Truth values as numbers " Link "Logic and comparison"    36}              Logic and comparison
 @{" Turn an expression into a statement " Link "Turning an Expression into a Statement"     0}  Turning an Expression into a Statement
 @{" Type " Link "Types"     0}                                 Types
 @{" Type of a variable " Link "Variable types"     0}                   Variable types
 @{" Type, 16-bit " Link "Indirect types"     0}                         Indirect types
 @{" Type, 32-bit " Link "Default type"     0}                         Default type
 @{" Type, 8-bit " Link "Indirect types"     0}                          Indirect types
 @{" Type, address " Link "Addresses"     0}                        Addresses
 @{" Type, array " Link "Tables of data"     0}                          Tables of data
 @{" Type, complex " Link "Complex types"     0}                        Complex types
 @{" Type, default " Link "Default type"     0}                        Default type
 @{" Type, direct " Link "Indirect types"    21}                         Indirect types
 @{" Type, dynamic " Link "Inheritance in E"   147}                        Inheritance in E
 @{" Type, E-list " Link "Lists and E-lists"     0}                         Lists and E-lists
 @{" Type, indirect " Link "Indirect types"     0}                       Indirect types
 @{" Type, list " Link "Lists and E-lists"     0}                           Lists and E-lists
 @{" Type, LONG " Link "LONG Type"     0}                           LONG Type
 @{" Type, LONG (definition) " Link "Indirect types"    21}              Indirect types
 @{" Type, object " Link "OBJECT Type"     0}                         OBJECT Type
 @{" Type, object elements " Link "Element selection and element types"    13}                Element selection and element types
 @{" Type, pointer " Link "PTR Type"     0}                        PTR Type
 @{" Type, procedure parameters " Link "Procedure parameters"     0}           Procedure parameters
 @{" Type, recursive " Link "Recursion"     0}                      Recursion
 @{" Type, STRING " Link "Normal strings and E-strings"    49}                         Normal strings and E-strings
 @{" Type, variable declaration " Link "Default type"    15}           Default type
 @{" Typed list " Link "Typed lists"     0}                           Typed lists
 @{" Unification " Link "Unification"     0}                          Unification
 @{" Unsigned and signed values " Link "Signed and Unsigned Values"     0}           Signed and Unsigned Values
 @{" Uppercase a string " Link "String functions"   171}                   String functions
 @{" Using a module " Link "Using Modules"     0}                       Using Modules
 @{" Using arg " Link "Any AmigaDOS"     0}                            Any AmigaDOS
 @{" Using modules, example " Link "Example Module Use"     0}               Example Module Use
 @{" Using ReadArgs " Link "AmigaDOS 2.0 (and above)"     0}                       AmigaDOS 2.0 (and above)
 @{" Using wbmessage " Link "Any AmigaDOS"     0}                      Any AmigaDOS
 @{" van Oortmerssen, Wouter " Link "Amiga E Author"     0}              Amiga E Author
 @{" Variable " Link "Variables and Expressions"     0}                             Variables and Expressions
 @{" Variable initialisation and automatic exceptions " Link "Raise within an Exception Handler"    54} Raise within an Exception Handler
 @{" Variable type " Link "Default type"    15}                        Default type
 @{" Variable, built-in " Link "Built-In Variables"     0}                   Built-In Variables
 @{" Variable, changing value " Link "Assignment"     0}             Assignment
 @{" Variable, declaration " Link "Variable declaration"     0}                Variable declaration
 @{" Variable, decrement " Link "INC and DEC statements"     0}                  INC and DEC statements
 @{" Variable, global " Link "Global and local variables"     0}                     Global and local variables
 @{" Variable, increment " Link "INC and DEC statements"     0}                  INC and DEC statements
 @{" Variable, local " Link "Global and local variables"     0}                      Global and local variables
 @{" Variable, procedure parameter " Link "Global and local variables"     0}        Global and local variables
 @{" Variable, same global and local names " Link "Global and local variables"    57} Global and local variables
 @{" Variable, same local names " Link "Global and local variables"    32}           Global and local variables
 @{" Variable, system " Link "Built-In Variables"     0}                     Built-In Variables
 @{" Variable, type " Link "Variable types"     0}                       Variable types
 @{" Variable, use in Assembly statements " Link "Assembly and the E language"     0} Assembly and the E language
 @{" Version, Kickstart " Link "System support functions"    83}                   System support functions
 @{" Vertical FOR loop " Link "FOR loop"     0}                    FOR loop
 @{" Vertical IF block " Link "IF block"     0}                    IF block
 @{" Vertical WHILE loop " Link "WHILE loop"     0}                  WHILE loop
 @{" View module contents " Link "Using Modules"    18}                 Using Modules
 @{" Voiding an expression " Link "Turning an Expression into a Statement"     0}                Turning an Expression into a Statement
 @{" Voiding, automatic " Link "Turning an Expression into a Statement"    20}                   Turning an Expression into a Statement
 @{" Wait for left mouse button click " Link "Intuition support functions"   327}     Intuition support functions
 @{" Waiting for Intuition messages " Link "Intuition support functions"   285}       Intuition support functions
 @{" wbmessage, using " Link "Any AmigaDOS"     0}                     Any AmigaDOS
 @{" WHILE loop " Link "WHILE loop"     0}                           WHILE loop
 @{" WHILE loop check " Link "WHILE loop"    22}                     WHILE loop
 @{" WHILE loop version of a FOR loop " Link "WHILE loop"    17}     WHILE loop
 @{" Whitespace " Link "Spacing and Separators"     0}                           Spacing and Separators
 @{" Whitespace, trim from a string " Link "String functions"   158}       String functions
 @{" Window flags " Link "Intuition support functions"    89}                         Intuition support functions
 @{" Window, close " Link "Intuition support functions"   122}                        Intuition support functions
 @{" Window, open " Link "Intuition support functions"    16}                         Intuition support functions
 @{" Window, output " Link "Built-In Variables"    34}                       Built-In Variables
 @{" Wouter van Oortmerssen " Link "Amiga E Author"     0}               Amiga E Author
 @{" Writing a character to file " Link "Input and output functions"    97}          Input and output functions
 @{" Writing to memory " Link "Maths and logic functions"   121}                    Maths and logic functions
 @{" X-coordinate, mouse " Link "Intuition support functions"   256}                  Intuition support functions
 @{" Y-coordinate, mouse " Link "Intuition support functions"   266}                  Intuition support functions
 @{" Zero exception (success) " Link "Raising an Exception"    73}             Raising an Exception
 @{" Zero fill field " Link "Input and output functions"    53}                      Input and output functions

@EndNode

