1682 lines
63 KiB
Plaintext
1682 lines
63 KiB
Plaintext
@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" "Introduction to Amiga E"
|
|
@Next "Understanding a Simple Program"
|
|
@Prev "Contents.guide/main"
|
|
@Toc "Contents.guide/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
|
|
`Reference Manual', 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" "A Simple Program"
|
|
@Toc "main"
|
|
|
|
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" "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 to the code, yet: 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. (If you don't have
|
|
your keyboard set up properly then you find that keys don't produce the
|
|
same characters that are printed on them--especially when use use the
|
|
shift key. In this case it will probably behave like a US keyboard,
|
|
although you should really fix this and set it up properly--see the
|
|
manuals that came with your Amiga.)
|
|
|
|
|
|
@ENDNODE
|
|
|
|
@NODE "Compilation" "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" "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.2e 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" "Understanding a Simple Program"
|
|
@Next "Variables and Expressions"
|
|
@Prev "main"
|
|
@Toc "Contents.guide/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" "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" "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" "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" "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" "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 (starting with a lowercase letter), 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" "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" "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" "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 we 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" "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" "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" "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" "Variables and Expressions"
|
|
@Next "Program Flow Control"
|
|
@Prev "Understanding a Simple Program"
|
|
@Toc "Contents.guide/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" "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" "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" "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" "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" "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, since they are just like local variables for the procedure.
|
|
(The only real difference between local and parameter variables is that
|
|
parameter variables are initialised with the values supplied as parameters
|
|
when the procedure is called.)
|
|
|
|
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)
|
|
|
|
Global variables are, by default, initialised to zero. Parameter
|
|
variables are, of course, initialised by the actual values passed as
|
|
parameters when a procedure is called. However, local variables are not
|
|
initialised. This means that a local variable will contain a fairly
|
|
random value when the code of a procedure is first executed. It is the
|
|
responsibility of the programmer to ensure no assumptions are made about
|
|
the value of local variables before they have been initialised. The
|
|
obvious way to initialise a local variable is using an assignment, but
|
|
there is also a way of giving an initialisation value as part of the
|
|
declaration (see @{"Initialised Declarations" Link "MoreExpressions.guide/Initialised Declarations" }). Initialisation of variables
|
|
is often very important, and is a common reason why programs go wrong.
|
|
|
|
|
|
@ENDNODE
|
|
|
|
@NODE "Changing the example" "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" "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" "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 "FloatingPoint.guide/main" }). (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" "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 "MoreExpressions.guide/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" "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, and the normal order in which the operations are performed is
|
|
left-to-right, just like the expression is written. 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, it would
|
|
have been:
|
|
|
|
2<1 AND -1=0
|
|
|
|
This is actually interpreted the same 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 "MoreExpressions.guide/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" "Program Flow Control"
|
|
@Next "Summary"
|
|
@Prev "Variables and Expressions"
|
|
@Toc "Contents.guide/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.
|
|
|
|
Another aspect of flow control is choosing between different pieces of
|
|
code to execute. For instance, if something goes wrong a program may need
|
|
to 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" "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" "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 }statementA@{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 be interpreted only
|
|
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" "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 }.
|
|
|
|
The @{b }IF@{ub } expression has the following form:
|
|
|
|
IF @{fg shine }exp@{fg text } THEN @{fg shine }expA@{fg text } ELSE @{fg shine }expB@{fg text }
|
|
|
|
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 (either
|
|
@{fg shine }expA@{fg text } or @{fg shine }expB@{fg text }, depending on the value of @{fg shine }exp@{fg text }), 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" "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 on the
|
|
selection variable. 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" "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.guide/main" }). @{fg shine }maxrange@{fg text } must be a positive constant
|
|
and the other constants must all 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" "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" "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.guide/main" }). 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" "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 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" "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" "Summary"
|
|
@Next "Format.guide/main"
|
|
@Prev "Program Flow Control"
|
|
@Toc "Contents.guide/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
|
|
|