home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Global Amiga Experience
/
globalamigaexperience.iso
/
compressed
/
development
/
heliosdemodisk3.dms
/
heliosdemodisk3.adf
/
Tutorials
/
HeliOSLanguageTutorial2.doc
< prev
next >
Wrap
Text File
|
1994-12-18
|
72KB
|
1,813 lines
------------------------------------------------
An Introduction to Elementary HeliOS Programming
------------------------------------------------
This introductory tutorial is intended to explain a few general ideas
which may help you get started with HeliOS.
Because simple once-only statements of fact are not the best way of
introducing a complex subject, we have provided tutorials which cover
similar ground in different ways.
Some of the ideas in this tutorial will be different expressions of
ideas related in other tutorials, and some of the material will be new.
Hopefully this many-faceted approach will help make some of the more
unfamiliar concepts accessible to most people, and once you are confident
enough to write your own first programs you will be able to pick up
further knowledge directly from the reference material as you need it.
So don't just say "Oh..we've already read this!" and gloss over things,
unless you already are very confident of your understanding, because
there may be some new ideas in here.....
---------------------------
Getting started with HeliOS
---------------------------
HeliOS is a Forth-like language, especially in its simpler aspects, and
the more sophisticated features of HeliOS build upon a central core of
functions which are closely related to fig-Forth.
This tutorial will discuss a few simple concepts which relate to Forth
and Amiga programming in general without delving into deeper aspects
of HeliOS. This is not a detailed HeliOS language lesson, and does not
deal in depth with programming the Amiga operating system and hardware.
It will not take long before you are able to write your own first HeliOS
program. If you follow the introductory instructions and get the small
demonstration programs working you will soon be all ready to start writing
real working programs which include text and graphics.
To help you get started with your own programs we include a standard
"start up and close down" mini-program which you can use as a general
basis for all your early experimental code. This "framework" program
will enable you to open screens and windows, get user input, print text
and display graphics: all the elements of simple programming in fact.
We also include several source code files which introduce slightly more
advanced techniques while still being quite accessible to beginners. It
is easy to modify these programs to make your own simple games and from
there you can progress to studying the more complex examples provided,
such as the full source code for the HeliOS "Defender" game.
It may be a little boring, but even if you are not new to Forth-type
lanuages please read through the introductory tutorials BEFORE trying
to actually change any of the example programs provided. This will help
prevent initial frustration, because HeliOS is a very unusual language
and a certain amount of insight into how HeliOS works is necessary even
for experienced programmers.
------------------------------------------------------
What do the terms "Compiling" and "Interpreting" mean?
------------------------------------------------------
The text which contains the program instructions you wish to give to the
computer is called "source" code, because it is the "starting" point for
a translation process. This translation produces the actual "executable"
code which is executed by the computer's CPU (central processing unit).
The process of producing machine-readable CPU executable code from the
human-readable source code is known as "compiling". Strictly speaking,
"compiling" is the term used to desribe the process whereby the source
code for a program is converted to executable code in the form of a file
which can be "run" or "executed" later.
Some computer languages, rather than compiling source code into executable
code as a whole, translate and execute each bit of source code as they go.
This process is called "interpreting". The latter languages run programs
very slowly because of the inefficient on-the-fly interpretation process.
They do, however, have the advantage that you can "try out" code at once
to see how it works: an "interpretive" language gives an instant response.
The pure "compiler" languages produce much faster final code, but in turn
they suffer from a rather serious disadvantage in that the process of
compilation is quite involved and time consuming. This means that the
programmer's task of compiling, testing, rewriting, and recompiling can
be a very slow and non-interactive (often frustrating) occupation.
HeliOS is a "compiler", but it also has an "interpretive mode" as well,
which is a good thing because it means that you can create fast compiled
programs AND test them interactively as you go. This feature of HeliOS
alone is a very good reason for using it as a "learning" language, and
the efficiency with which it both "interprets" and "compiles" lifts it
above any other language on the Amiga in this respect.
------------------------
HeliOS Program Structure
------------------------
The first thing to learn is the correct way to write your "source code",
because any computer language can only understand code in a very specific
text format. Fortunately there are very few "rules" to learn with HeliOS
and there are no constraints such as "line numbers", or "strictly typed
variables".
Traditional Forth did employ a quite rigid and unusual form of source code
stored in special "blocks", but HeliOS allows great freedom of text layout
within the framework of a few simple but necessary rules.
Some computer languages simply allow a whole program to be one single long
"stream" of code, but this can be highly confusing. The more sophisticated
languages allow code to be broken down into easy-to-handle sub-sections, or
"subroutines", which can in turn be logically organised in a clear and
functionally efficient manner. The latter type of language is called a
"structured language".
HeliOS programs are highly structured, and the language uses a collection
of subroutines, often called "Words", which are created using a source code
construct called the "colon definition". This name is used because each
new subroutine definition starts with the colon ":" character.
Within the "colon definitions" which define your functional code, there may
be used all the usual logical constructs such as "IF-ELSE-THEN", "DO-LOOP",
"BEGIN-UNTIL" etc etc. All these constructs are easy to use and allow you
to create neat and easy to read logically structured code.
In effect HeliOS programming consists in defining new words which extend the
language itself, and as such is a very flexible and intuitive process. You
can lay out programs in a very free way, and you may use any text editor
which produces standard ASCII files, although it well generally be most
convenient to use the integrated HeliOS editors because you can compile
code directly from there.
-------------------
"Colon Definitions"
-------------------
The colon definition allows you to define an action and give a name to the
resulting functional unit. The new "subroutine", or "Word", can then
be used by simply entering its name in later source code. You have actually
created a new operator which is just as much a part of the language as the
initial HeliOS Core vocabulary functions.
The start of a new subroutine is designated by a colon, and, after the code
specifying what the new word does, we end the definition with a semicolon.
Look at the example below:
: NEWWORD |<--------definition-------->| ;
Here you can see the colon and the semicolon with the definition placed in
between. Note that immediately following the colon is the word NEWWORD,
and, as you may have guessed, this is the name of our new subroutine.
Remember that YOU choose the name of the new function: it can be anything
you like, but always try to use distinctive and descriptive terms to make
your code more comprehensible to you. If you choose names carefully your
code can be made almost as readable as English language. On the other hand
it is very easy to write very incomprehensible code indeed......
A lot of your HeliOS code will consist of the use of the colon definition,
so you will soon become familiar with it. We will give plenty of examples
later in the tutorial.
---------------------------------
HeliOS "WORDS" and the dictionary
---------------------------------
HeliOS subroutines are called "WORDS", the total set of words available is
called the "VOCABULARY", and the place where all the words are stored in
the computer's memory is called the "DICTIONARY".
Because HeliOS source code is concerned with very "linguistically" oriented
activities, and because the definition and use of language is a very vital
part of HeliOS, the term "WORD" tends to become a rather overworked part of
HelIOS terminology. This all stems from traditional Forth usage.
Historically Forth programmers have always referred to subroutines and
their definitions as 'WORDS', but this can be confusing because the term
WORD was used in several different ways in Forth computing parlance -
1. It defines a quantity of memory - 2 bytes or 16 bits. ( see later )
2. It is used to refer to the basic functional units of the Forth
Language in terms of WHAT THEY DO operationally.
3. It is used in the English Language sense to refer to the actual NAME
of the subroutine - the actual letters which you type to define it.
A little care has to be taken, when you are first starting with HeliOS, to
understand the context in which the word "WORD" is used!
All the commands and subroutines that HeliOS uses, including both your own
subroutines and predefined HeliOS word definitions are stored in the HeliOS
'dictionary'.
As each new definition is added, the free space in the HeliOS dictionary is
reduced. This space has a fixed limit, and you can always see how much room
is left in the dictionary by looking at the status display at the top of
the HeliOS screen. When the dictionary is full you can write no more code,
but since HeliOS compiled code is VERY compact this would mean that you had
already written a very large program indeed.
You can list the contents of the Dictionary simply by typing "VLIST" at the
command line (described later), or using the menu options in the Interpreter
"HeliOS" menu.
It is important to understand how the dictionary works because the general
compilation method used by HeliOS is quite unlike that of most other Amiga
languages.
Basically this is what happens -
1. You create a subroutine by typing in one or more lines of source code.
2. The executable code is then "compiled" and stored in the dictionary
in a form which can be "understood" by the computer.
3. The name you gave the new "word" is stored SEPARATELY in a special list
rather like an index, which allows the word to be found and used later
merely by entering its name.
( SPECIAL NOTE about 3. above:
HeliOS is very different from traditional Forth in the way that it
stores word names in a separate list. If you are a seasoned Forth
programmer, or have a book on traditional Forth, you should read and
remember the following note, as it will beneficially effect your whole
programming style.
When a HeliOS program is finally run the list of word names is no
longer needed. This means that when you produce completed stand-
alone programs the list of names can be omitted. If you think about
it you will see that this is very useful, because it means that you
can use long descriptive names for your subroutines without having
to worry about them cluttering up your program later.
This may seem very obvious, but traditional Forth actually stored the
word names permanently within the program code and you may find books
which advise you to use short names for this reason. Using HeliOS
you can relax and use word names as long as you like - just try to
make your names useful and descriptive. )
Every time these three steps are performed the compiled code is added to
the dictionary. If you recompile a subroutine and do not change its name,
the earlier version(s), although still stored in the dictionary, will be
left in place but superceded by the latest addition. This means that your
latest definition will always be the one used in response to typing the
subroutine name, but the "old" definitions will still be there hidden in
the dictionary.
During a typical session you may well work on a program by continually
recompiling and testing code. If you make no attempt to clear previous
additions to the dictionary then it will be filled quite quickly.
The dictionary can be totally cleared back to the fixed CORE dictionary
( the set of standard words which are available at startup ) by using the
expression:
FORGET **CORE**
Placing this at the start of a program source code file ensures that you
can keep recompiling the source code without subroutine definitions being
duplicated and without the dictionary gradually being filled up.
We will from now on call the basic set of HeliOS commands, which is ALWAYS
available, the CORE dictionary (or vocabulary), and all the subroutines
defined in your own code as the USER dictionary (or vocabulary).
Here are three command words to list the vocabularies:
CVLIST -> List the CORE vocabulary
UVLIST -> List the USER vocabulary
VLIST -> List the CORE vocabulary followed by the USER vocabulary
------------------------------------
Computer Memory and the HeliOS Stack
------------------------------------
Memory is the basic storage medium for program code and data.
Memory can be thought of as a series of cells, each of which can hold a
numerical value, and the way in which each value is interpreted is largely
determined by the code within your program.
HeliOS uses a special device called a STACK, which is actually just a small
organised subsection of the large general memory pool. Rather than being
randomly accessed in any order, the stack is accessed sequentially like a
pile of plates, or a deck of cards.
Data is, in general, placed on the top of the stack and then removed when
it is needed later.
As more and more items are stored on the stack it grows in size, and the
oldest items, those placed on the stack first, are left at the bottom.
The HeliOS stack is employed to store sets of numbers which are going to be
used almost at once by other subroutines, and can be regarded as a quick
temporary store. It can also be looked upon as a "channel" of information
between sequential operations. Typically one operation will put a number
onto the stack, and the next will take the number off the stack and use it.
You can think of it almost as a type of "messenger" carrying data between
different parts of your program: a kind of "dumb waiter".
Many HeliOS words, including your own program subroutines, look for and
return values on the stack, and this process is called "parameter passing".
In the past many would-be Forth programmers were initially terrified of
using the stack because they had never used such a thing and had perhaps
used other languages which employed NAMED VARIABLES rather than a stack.
Actually you will soon see that the stack is ridiculously easy to use and
gives you a lot more programming power than the restrictive use of variables
for all parameter passing. In HeliOS you can use the stack or you can use
named variables, or both together: so you have more power and more choice.
HeliOS provides a large number of words for manipulating the stack,
and these should be learned as soon as possible - they will soon become
familiar since they are in constant use in ALL your HeliOS code. This is
because you are constantly needing to adjust the position of data items
on the stack, as well as adding, deleting, and duplicating items.
Traditional Forth had just a few stack control words, and managed any more
complex operations needed by combining many of these simple words together.
Because the names used in Forth for stack operators are short and cryptic,
complicated combinations of them are very unreadable. Not only this, but
use of a lot of generalised words to do a job rather than one specific word
is very inefficient. This was THE major problem with early Forth systems.
This problem of "stack control" is one of the weakest parts of traditional
Forth, and is largely responsible for Forth code getting a reputation for
being very unreadable. This is a shame, because Forth was potentially the
most "readable" of all computer languages, and it was only the limited
vocabulary of early Forth systems which caused the difficulty.
HeliOS has removed the necessity for worry over stack manipulation
by providing the most complete set of specialised words ever available
in a Forth-type language. Try to gradually incorporate more and more of
these words into your knowledge of HeliOS, so that you can use just the
right specific word for the job rather than a series of less appropriate
ones.
HeliOS has adopted another totally new philosophy which departs from Forth
tradition: all the stack control words in HeliOS are machine coded for
maximum speed and efficiency.
We have dwelt perhaps overmuch on the stack, because the use of the stack
will be really important throughout all of your HeliOS programming. The
concept of always using the minimum of stack control words throughout
your code is VERY important if your programs are to be readable, easily
maintained, and fast in operation.
Before leaving this important subject, here is a very quick practical
example of stack manipulation so that you can see what it is all about.
Take a stack with four numbers on it: 1, 2, 3, 4
Imagine that the "4" is at the top, and the "1" is at the bottom.
Suppose that we want to duplicate the third number from the top and
place a copy of it on the top of the stack. ( Believe it or not, this
sort of thing is quite commonly required! )
So we need to operate on our initial stack to get: 1, 2, 3, 4, 2
Let us assume that we have four stack operators:
DUP - this duplicates the number on top of the stack
eg. 1, 2, 3, 4 -> 1, 2, 3, 4, 4
SWAP - this exchanges the top two stack items
eg. 1, 2, 3, 4 -> 1, 2, 4, 3
DSWAP - this exchanges the top two "double" stack items
eg. 1, 2, 3, 4 -> 3, 4, 1, 2
ROT - this REMOVES the third number on the stack and
puts it onto the top
eg. 1, 2, 3, 4 -> 1, 3, 4, 2
How do we solve our simple problem?
Why not try it as an exercise on paper?
We could do the following: 1, 2, 3, 4
ROT ->
1, 3, 4, 2
DUP ->
1, 3, 4, 2, 2
ROT ->
1, 3, 2, 2, 4
DSWAP ->
1, 2, 4, 3, 2
ROT ->
1, 2, 3, 2, 4
SWAP ->
1, 2, 3, 4, 2
Success! We did it! This way is slow, but it DOES work.
( Actually it can be done quicker than this - did you manage it? )
But look......we have the following series of operators:
"ROT DUP ROT DSWAP ROT SWAP"
This is horrible to read, and even worse to debug when combined with a lot
of other similar sequences. It is also very time consuming to compile and
execute, since it takes SIX words to do one simple job. If we could do
this operation in ONE word we should have SIX times better code - it is
as simple as that.
HeliOS would do the following in one word - and it would be a very fast
internally machine coded word too.
HeliOS would say: 1, 2, 3, 4
3PICK ->
1, 2, 3, 4, 2
So we have used the special operator "3PICK" = "pick out the third item"
We have written a program which compiles AND runs SIX times faster than
the first method.
This kind of thing is fundamental to good HeliOS programming, and you will
constantly come up against coding tasks exactly like the above example.
------------------------
The HeliOS stack display
------------------------
To help you get accustomed to the working of the stack, HeliOS has a
permanent stack display at the top of the Interpreter window.
Try doing a few calculations and manipulations like the examples above
and watch the stack display. This will soon give you a feeling for how
the HeliOS stack works, because seeing the numbers change in the set of
cells displayed graphically on screen is an excellent aid in visualising
stack operations.
----------------------------------------------------------------
Passing Parameters between HeliOS Words and using Stack Diagrams
----------------------------------------------------------------
Let us take, as a simple example, the HeliOS Word "FPENSET". This
word sets the foreground text pen colour, which is simply a number. On
a four colour screen the text could be displayed in colour 0, 1, 2 or 3.
Let us assume we are starting from an empty stack.
Our word FPENSET needs to know what colour we want it to use, and this is
done very simply in HeliOS by passing the colour number as follows:
1 FPENSET for "colour 1"
or 3 FPENSET for "colour 3"
Here the "parameter", the colour number, is "1" (or "3"), and is written
in your source code as a simple number preceding the word FPENSET.
This looks very natural and simple, and indeed this simplicity is a very
good feature of HeliOS, but a little more is happening than is apparent.
What actually happens is that the number "1" is stored on the stack until
it is used by FPENSET, which leaves the stack empty. This situation is
represented by the "stack diagram", which you will see used throughout
the HeliOS Dictionary definitions. This is a means of representing what
happens to the stack during the operation of a HeliOS Word.
In the case cited above we have a stack diagram as follows:
n - - -
The "n" represents the colour number which the word FPENSET expects to
find placed on the stack. The three "-" signs signify the computing
process as FPENSET does its work, and the fact that there is no number
afterwords means that FPENSET actually uses internally and removes its
single parameter, leaving nothing on the stack itself.
The parameter to be passed to the subroutine is stored temporarily on
the stack, the subroutine then removes it and, in this case, returns
with the stack clear.
This method is crucial to HeliOS operation. Several parameters can be
passed to subroutines via the stack, as you will see in the examples
given below. The word GFXRECTFILL, for example, uses four parameters
denoting the corners of a box to draw a filled rectangle.
Many subroutines use the stack to return parameters, and your program
must constantly keep track of the stack to ensure that this process of
passing parameters is kept in order.
The HeliOS words used to make ordinary arithmetic calculations all get
their parameters from the stack, operate on them, and then return the
result of the calculation on the stack.
In a simple addition two parameters are needed, and the result, which
is a single parameter, is returned on the stack -
3 5 + add two numbers 3 and 5, leaving the result on the stack
. display on screen the value on the stack ( the "result" )
The stack diagrams of these two words would be:
"+" n1 n2 - - - n3
"." n3 - - -
---------------
Using Variables
---------------
While HeliOS uses the stack for most of its short term parameter passing
operations, ordinary memory can be used for data storage on a more long
term basis. Languages like BASIC and PASCAL use named variables to access
the memory in which the data is stored without involving the programmer
with the actual "physical" memory address, or indeed with "stacks".
HeliOS can do the same thing if required, and while the stack is much more
efficient for most parameter passing (and gives HeliOS a significant speed
advantage), there are many occasions where it is best to use variables.
A variable can be created using the word VARIABLE and data can be moved in
and out using the two HeliOS words "!" (which is pronounced "store") and @
(which is pronounced "fetch").
When a variable is created in HeliOS it always has to be initialised, but
if no particular initial value is needed you can always set the initial
value to zero.
A variable created in this way is stored in the dictionary.
For example,
0 VARIABLE MILES
will create a VARIABLE called "MILES" initialised to zero.
In a similar manner,
50 VARIABLE MILES
will create a VARIABLE called "MILES" and initialise it to 50.
We can now get and display the memory contents referenced by the word
"MILES" as follows:
MILES @ .
(or a shorter version: "MILES ?" which does exactly the same thing.)
What is actually happening here?
MILES \ Puts the address of the variable on the stack,
\ or, more accurately, the address of the memory
\ cell where the the value 50 is stored
@ \ Gets the data stored at that memory address and
\ puts it on the stack, having first removed the
\ address from the stack
. \ Displays and removes the "top of stack" value
We have not specifically accessed memory numerically - we have just asked
for the contents of the VARIABLE defined by the name "MILES".
This use of easy to remember words rather than numbers is a great help in
writing easily understood code.
In a similar manner we can store a value in a variable using "!" ("store")
12 MILES !
will store the value 12 in the memory location defined by the word MILES.
---------------------------------------------
A little note on 16-Bit and 32-Bit Addressing
---------------------------------------------
A computer deals with binary numbers, which are actually just like simple
two-state "on or off" switches. These are each said to contain one "bit"
of information, and can only represent the numbers 1 and 0.
A single cell of memory contains an 8-bit number, which is a collection of
8 bits, and is called a "byte". This can represent a decimal number of up
to "255", which is still a rather small unit of information.
Because a byte is such a small "chunk" of information, we often use a much
larger unit of 16-bits, 2-bytes, which we call a "word".
Above this we have 32-bit numbers which are 2 "words" or 4 bytes in length,
and these are often referred to as "long" or "longwords".
So....the data which we store is usually in the form of 1, 2, or 4 byte
numbers.
Computers use similar numbers to define positions in memory, often called
memory "addresses", so that they know where to store and fetch information.
On a machine like the Amiga, memory is "addressed" by 32-bit, or 4-byte
"long" numbers.
HeliOS uses a little "trick" to avoid the use of these very large numbers
all the time. It defines addresses within the HeliOS dictionary as 16-bit
numbers and "internally" adds a further number to these addresses to get
the true 32-bit address. So HeliOS can use 16-bit addressing or 32-bit
addressing depending on whether an address is in dictionary memory space.
Don't worry too much about these things for now; we simply mention them
here to enable the code example later to be more fully comprehended. We
will give a couple of examples here to clarify how HeliOS defines different
length numbers and addresses, but do not attempt to learn this now, and do
not worry if you cannot follow all the explanation.
------------------------------------------------------------------
The HeliOS Dictionary is a 16-bit addressed, 16-bit data structure
------------------------------------------------------------------
What does this "imposing" statement mean?
To keep things simple for now we should just point out that HeliOS uses
16-bit numbers for its standard mode of operation. Numbers on the stack
are stored as 16-bit "cells", and 32-bit numbers are stored as two of
these standard cells. HeliOS stores 8-bit numbers on the stack again in
a 16-bit cell, but ignores the top byte of the number.
A 16-bit number is often referred to in HeliOS as a "single number".
A 32-bit number is often referred to in HeliOS as a "double number".
As well as using 16-bit data items as "standard", all memory addressing
within the HeliOS dictionary memory space is usually specified by 16-bit
numbers also (although any 16-bit HeliOS address can also be specified as
a 32-bit address if required).
In general then, HeliOS, like traditional Forth, is largely concerned in
its internal operations with 16-bit numbers.
Double word 32-bit addressing specifies a memory location directly as one
large number. As its name implies, 4 bytes of storage are needed to handle
this number. This 32-bit addressing is always used in conjunction with
Amiga library calls, and cannot be avoided. A 32-bit address is stored
on the HeliOS stack as two 16-bit numbers, but there are many HeliOS commands
which treat this easily as one 32-bit entity.
A 32-bit address is often referred to as a "long" address, or a "longword"
address.
16-bit addressing is ONLY used to specify memory addresses within the main
HeliOS dictionary. Remember always that this addressing technique specifies
a memory location as an offset from a point of reference which is the start
of the HeliOS dictionary.
Here are two HeliOS command words which translate between 16-bit and 32-bit
addressing for any addresses within the HeliOS dictionary:
W>L ( a1 - - - l1 ) -> Converts a 16-bit address to a 32-bit address
L>W ( l1 - - - a1 ) -> Converts a 32-bit address to a 16-bit address
--------------------------------------------------------------
How HeliOS specifies 16-bit and 32-bit addressing and numbers.
--------------------------------------------------------------
Addressing can be very confusing and people often get mixed up with 16
and 32 bit data values and 16 and 32 bit addresses. To avoid confusion
when using these differing quantities we need to use a regular notation.
HeliOS uses a standard notation of:
a "D" prefix for double length data
an "L" suffix for long addressing
An example using VARIABLES may help clarify the matter:
Both 16-bit and 32-bit data storage variables can be created as follows:
50 VARIABLE MILES
Creates a 16-bit variable called 'MILES' and initialises
it to 50.
This variable is referenced by a 16-bit address.
Use of the word 'MILES' puts a 16 bit address on the
stack, indicating the memory location where the number
50 is stored as a 16-bit number in the HeliOS dictionary
memory space.
50. DVARIABLE MILES
Creates a 32-bit variable called 'MILES'. The full stop
after the "50" indicates that this is a 32-bit number.
In this case the 32-bit data value is stored at a 16-bit
address, and use of the word "MILES" returns this 16-bit
address where the 32-bit number "50." is stored.
Note that the number 50 itself could be stored in an
8-bit space: the data size refers to the storage space
and not the size of the actual number stored there.
The D prefix signifies a double length data variable -
remember this, as it is the standard form of notation.
50 VARIABLEL MILES
Creates a 16-bit variable called 'MILES' stored at a
32-bit or Long address. Use of the variable 'MILES'
returns a 32-bit number on the stack representing the
longword address where the 16-bit value is stored.
The L suffix signifies a long address, and again this is
a standard notation for "long" 32-bit addressing.
50. DVARIABLEL MILES
Creates a 32-bit data variable stored at a 32-bit address.
Note the 32-bit data indicated by the "." after the "50"
and the "D" prefix to indicate a 32-bit data variable.
Note again the use of the "L" suffix to indicate the long
addressing mode.
The above example illustrates standard HeliOS notation, which you should
become familiar with as soon as possible.
Remember that the D prefix always relates to double length data and the
L suffix relates to long addresses.
It is important to remember here that variables within the main HeliOS
dictionary can actually be 16-bit addressed or 32-bit addressed. Those
given 16-bit addresses can be converted to 32-bit addresses using the
HeliOS Word "W>L" ("word-to-longword"). An address thus converted may be,
in turn, restored to 16-bit form using the reverse operation "L>W".
Data values can easily be converted from single to double size using the
word "S>D" ("single-to-double"), but values can only be converted from
double to single if they are less than 16-bit in "numerical" size.
Unsigned single numbers can be converted to double numbers by simply adding
a zero to the stack, since this zero represents the high word of the new
32-bit value.
It is important to handle parameter passing (via the stack) correctly if
your programs are to run satisfactorily, so you have to be careful to use
16 and 32-bit values and addresses properly. If a subroutine expects a
double word parameter (4 bytes) passed on the stack, the computer will
probably crash if you only pass a single word parameter of 2 bytes!
---------------------------------------
Using "Text Strings" in HeliOS programs
---------------------------------------
The term "String" is used in relation to text storage in memory. Since
computers only deal with numbers we have to represent text as a "string"
of numeric codes in memory.
Each text character is defined by a numeric code called an "ASCII" value,
which is a standard code used for representing letters as numbers in the
computer's memory.
A series of continuous bytes in memory which represent text ("ASCII")
characters make up a text "string".
Strings are handled either as "counted strings", which are always stored
along with a number indicating their length, or "null terminated strings"
which simply carry on in memory until a "0" character is encountered.
In both cases a memory address is used to specify the first byte of the
string, and this number is used to manipulate the string. As with numeric
data a string "address pointer" can be a simple number on the stack, or
may be "named" like a variable.
The first byte of a counted string is always called the "count byte" and
is a number representing the total number of text characters in the string.
In the case of the "null terminated" string the first byte of the string
is simply the first character of the string itself, which continues on in
memory until a null value "0" occurs: hence its name.
Counted strings have limited length, since the single "count" byte has a
maximum value of 255. Null terminated strings, on the other hand, can be
of any length.
Traditionally Forth used counted strings, but the Amiga operating system
uses null terminated strings. HeliOS has comprehensive support for
both types, as well as easy conversion from one to the other.
HeliOS has an extra useful feature in that counted strings all have
a null terminator as well. To access a counted string as "null terminated"
all you have to do is increment the address of the string by one, thus
moving forward past the initial "count" byte to the first character.
HeliOS has a large number of string handling routines, many of which
handle either 16-bit or 32-bit addressing. As a general rule, handle all
strings as 16-bit addressed in simple programs unless you need to pass the
string to an Amiga library function. In this case you can easily convert
to a 32-bit address using "W>L" as required.
--------------------------------------------------------------
A very simple and useful HeliOS string handling word - "LIT$".
--------------------------------------------------------------
Using LIT$ within Colon definitions
LIT$ is used within a colon definition to allow compilation of a counted
string within your program code. The text string must be enclosed between
two dollar ("$") characters, as this example shows:
: PRESSMESSAGE LIT$ $Press SPACE-BAR To Continue$ ;
This example creates a new word PRESSMESSAGE, which employs "LIT$" to store
the text between the two dollar characters ("Press SPACE-BAR To continue")
within the dictionary. When you later use the word PRESSMESSAGE the 16-bit
address of the string is returned on the stack. It can then, for example,
be printed out to the screen using the word "$." in another word as follows:
: SHOWPRESMESSAGE PRESSMESSAGE $. ;
You will find this little word "LIT$" VERY useful indeed. We use it in
the example program below, and you should learn to use it yourself in your
own programs as soon as possible.
-------------------------------------
General INPUT and OUTPUT using HeliOS
-------------------------------------
Obtaining User Input
HeliOS has a general purpose input word "KEY". This word causes a program
to wait for an input event to occur. Input events include keyboard entry,
mouse button depression, mouse movement, gadget selection, menu selection
or ticker activation. We use the word "KEY" because traditional Forth used
this word, although it only accessed keyboard events, unlike the more
extended HeliOS version which handles ALL events.
The user input word "KEY" will report input events from whatever active
window YOU specify. You can designate ANY window as the current input
window using the HeliOS special word "MAKEINWINDOW". This is an
immensely powerful and important word, as it includes within itself a
whole "sub-program" which in any other Amiga language you would have to
write for yourself. This "sub-program" sets up a special task to monitor
and translate all input events, and has many very sophisticated features
unique to HeliOS. All this power translates, from your point of view, to
a very easy use of the single word "KEY" - all the hard work is done for
you!
-------------------------------------------------
Sending Output to the User via the screen display
-------------------------------------------------
There are two basic types of screen text output - console output and graphic
text output.
Text characters are usually written to console windows in streams, which
have full scrolling, cursor movement, and text formatting facilities etc.
In general all dynamic, changing text output is handled by "console" type
displays.
Graphic text output does not have these "text control" features and all
text is placed on the screen as a static graphic "drawing". This means
that, for example, text can only be deleted by overwriting the screen area
occupied by the graphic image of the text.
In general graphic text output is used for "painting" a graphic display with
static text.
Both kinds of text are fully supported by HeliOS, but the following
simple examples use "console" text output for simplicity. Note that this
console output is not always simple on the Amiga, and in other languages
quite a lot of programming is required to set up any console output.
HeliOS is unique in the power of its automated functions, and, as you will
see, console text output has been made very powerful and easy.
As a matter of interest, HeliOS has two powerful sub-programs which
fully automate the setting up of all console text output and graphical
operations within ANY designated window on ANY screen.
Quite large programs would have to be written by YOU in any other language
to achieve this functionality of HeliOS, which requires you to use just ONE
word to set up each sub-program:
"MAKOUTWINDOW" - sets up a VERY sophisticated console handling system
with TEN automated text "streams".
"MAKEGFXWINDOW" - sets up an automated graphics library handling system
with single word operators for most graphic functions.
Our final example program below will show you how to use these functions.
-------------------------------------
A FIRST TUTORIAL PROGRAMMING EXERCISE
-------------------------------------
Our tutorial program will start with a line of code which clears all words
from the user dictionary, leaving just the CORE vocabulary -
FORGET **CORE** \ Get rid of any old USER defined words
The "\" character denotes an "end of line comment", and anything following
this is ignored by the compiler. Always add plenty of descriptive comments
to your code in this way, so that you know what is going on.
Note here that ALL words in HeliOS source code should have a space before
and after them. This is absolutely vital, and note that a space is also
needed both before and after the "\" character, because this is also a
HeliOS Word.
To summarise these points, the above line of code has:
At least one space
The word "FORGET"
At least one space
The word "**CORE**" telling FORGET to clear all words back to CORE
At least one space
The word "\" which tells us that the rest of the line is a comment
At least one space
The words "Get rid of any old USER defined words" - the comment
Now we will add a "colon definition" to our program.
FORGET **CORE** \ Get rid of any old USER defined words
: SAYHELLO ." HELLO WORLD" ; \ Make a word called SAYHELLO
The colon definition above will create a new subroutine called SAYHELLO.
Let us look at it's structure. It has -
At least one space
A ":" to start the definition
At least one space
A descriptive label, "SAYHELLO"
At least one space
The definition " ." HELLO WORLD" "
At least one space
A ";" to finish the definition
At least one space
A "\" which tells us that the rest of the line is a comment
At least one space
The words "Make a word called SAYHELLO" - the comment itself
We now have a small program:
FORGET **CORE** \ Dispose of any old USER defined words
: SAYHELLO ." HELLO WORLD" ; \ Make a subroutine called SAYHELLO
The next thing of interest is the definition ." HELLO WORLD".
This can be split into three parts as follows.
<SPACE> ." <SPACE> HELLO WORLD "
The first part is the HeliOS word ." which tells the HeliOS system to output
to the screen the words following it up to the next " character.
The second part is the expression HELLO WORLD, which is the message we want
to display.
The third part is the quote character " which tells the HeliOS system that
our enclosed quotation has ended. The double quote " is not a HeliOS WORD
and does not need a space before it. It is called a delimiter and merely
acts to delimit the end of an enclosed text message "string".
To use the new word (subroutine) all we need to do is either type it at
the command line after compiling our program, or include it in our program
code after the definition.
--------------------------------------
Entering and compiling our new program
--------------------------------------
There are two ways of entering code. We can either use an editor or we can
type in code at the the command line. The editor option is perhaps better
in most cases because code can be saved to and loaded from disk files.
The command line has a circular "history" buffer and is useful for testing
small fragments of code which are being continually modified. It is very
quick for small code testing jobs, but cannot be saved to disk.
We will use an editor in this tutorial example, as follows:
1. Load HeliOS: the interactive screen appears at once.
2. Click the "Ed 1" button at the top of the screen to enter "Editor 1".
3. Now type in the following code -
( N.B.
This text was intended to be used from a printed page.
If you are using this text in the form of a disk file, you may already
be viewing it in one of the HeliOS editors.
In this case you can simply run the sections of code directly without
having to type them in. )
FORGET **CORE** \ Dispose of any USER defined words
: SAYHELLO ." HELLO WORLD" ; \ Make a word called SAYHELLO
SAYHELLO \ Use the new word we have created
WAITSPACE \ Wait for the space bar to be pressed
4. Compile the section of code.
This action will take you into the Interpreter and run the program.
This is a program which actually does something. It will print to the
screen the message "HELLO WORLD". Note that you can now type SAYHELLO
at the command line and the message "HELLO WORLD" will appear on screen.
Note also that you can use the up-arrow cursor key to bring back all the
previously typed command lines and reuse them - this makes use of the
circular command line "history" buffer mentioned above.
The next thing to do, perhaps, is save the code to a disk file, so.......
5. Repeat step 2 to reenter the Editor, then select 'Save As' from
the 'Load/Save' menu to access the HeliOS File Requester and
save the file.
Note that each time you resave a file with the same name as before
HeliOS will create a backup file for you automatically.
Having made a small working program we can now start to do some more
interesting things with it.
Listed below are a number of variations on our program for you to try.
Use the editor again to modify the code already entered, then use the
method outlined above to save and execute your code.
Try each of the following variations:
( Note that you can omit the comments if you like )
: SAYHELLO \ This version changes the output text position
10 10 CURPUT \ Set the text output position ("PUT" the "CURSOR")
." HELLO WORLD" \ Say hello
;
: SAYHELLO \ This changes the output text position and colour
3 FPENSET \ Set the foreground pen - text colour
1 BPENSET \ Set the background pen - text background
10 10 CURPUT \ Set the text output position ("PUT" the "CURSOR")
." HELLO WORLD" \ Say hello
;
: SAYHELLO \ This displays the message 4 times in line
4 0
DO \ Loop 4 times
." HELLO WORLD" \ Say hello
SPACE \ Put a space between messages
LOOP
;
: SAYHELLO \ To display the message 4 times on new lines
4 0
DO \ Loop 4 times
CR \ "Carriage Return" = Go to start of next line
." HELLO WORLD" \ Say hello
LOOP
;
Now for a more interesting one........
: SAYHELLO \ This repeats the message 4 times on new lines in a box
3 FPENSET \ Set the foreground pen - text colour
1 BPENSET \ Set the background pen - text background
1 GFXSETAPEN \ Set the graphics drawing colour (box colour)
2 GFXSETOPEN \ Set the graphics outline pen colour (box outline)
1 GFXOUTLINE \ Switch on graphics OUTLINE mode
10 \ "x" pos, in pixels of the box's top left hand corner,
\ measured from top left hand corner of screen
45 \ Top left "y" pos
150 \ Bottom right "x" pos
90 \ Bottom right "y" pos
GFXRECTFILL \ Draw a filled rectangle (draw box)
0 GFXOUTLINE \ Switch off graphics OUTLINE mode
4 0
DO \ Loop 4 times
CR \ "Carriage Return" = Go to start of next line
4 CURFW \ Move the "CURSOR FORWARD" to give a margin
." HELLO WORLD" \ Say Hello
LOOP
;
And now an even more interesting one........
: SAYHELLO \ This repeats the message 4 times on new lines in a box
3 FPENSET \ Set the foreground pen - text colour
1 BPENSET \ Set the background pen - text background
1 GFXSETAPEN \ Set the graphic drawing colour (box colour)
2 GFXSETOPEN \ Set the graphics outline pen colour (box outline)
1 GFXOUTLINE \ Switch on graphics OUTLINE mode
10 \ "x" pos, in pixels, the box's top left hand corner,
\ measured from top left hand corner of screen
45 \ Top left "y" pos
150 \ Bottom right "x" pos
90 \ Bottom right "y" pos
GFXRECTFILL \ Draw a filled rectangle (draw box)
0 GFXOUTLINE \ Switch off graphics OUTLINE mode
4 0
DO \ Loop 4 times
4 \ Start at 4th position on line
I 2 + \ Start at 2nd line + LOOP INDEX
CURPUT \ PUT the CURSOR
." This is line" \ Print "This is line"
I 1+ \ Increment the LOOP INDEX + 1 which is stored
\ on the stack, (the index starts at 0)
. \ Print the index number (stored on the stack)
LOOP
;
**************************************************************************
----------------------------------------
Using Amiga Libraries from within HeliOS
----------------------------------------
Amiga Libraries are special code modules which are provided to help you
with various programming tasks, and are very simple to use. Libraries are
either present within the Amiga ROM (Read Only Memory), or may be loaded
from disk.
The method of accessing a library is:
1. OPEN the library The Amiga loads and prepares it for use
2. CALL library routines You will need a reference book for definitions
4. CLOSE the library When you have finished with it
Many Amiga library routines are included in HeliOS as part of the CORE
dictionary. These functions are pre-written "interfaces" to specific Amiga
library calls and do not require you to address the library directly.
In addition, the main and most useful libraries are automatically opened for
you when HeliOS starts up and closed when HeliOS closes down.
These are the DOS, EXEC, GRAPHICS, LAYERS, and INTUITION libraries.
If you do have to open a library yourself there is a simple to use HeliOS
word called OPENLIB, which opens a library and returns the 32-bit library
base address on the stack as follows:
First, in our example we are going to open "diskfont.library", so we need a
DVARIABLE to store the library base address when we have opened it.
D0 DVARIABLE DFONTBASE \ Create a 32-bit variable DFONTBASE
Now open the library.........
LIT$ $diskfont.library$ \ Put counted library name string on stack
0 \ Put library revision number on stack
OPENLIB \ OPEN the library
DFONTBASE D! \ Store the library handle
Having done this, always check to see that the new base variable is not
still zero, in which case the library has failed to open for some reason
and you need to sort out the problem.
Closing a library:
First remember that you only need to close libraries that you yourself
have specifically opened. You do not need to close the standard libraries
handled for you by HeliOS system.
To close a library put the library base address on the stack and use the
word CLOSELIB like this:
DFONTBASE D@ CLOSELIB
That's all there is to it...................easy!
When a library is open and you want to use it, you need to know 3 things:
1. What is the library base offset for the routine you wish to call?
This is found from Amiga documentation and will always be a negative
number.
2. What "parameters" does that library call require before using it?
3. What results are returned after completion?
These details are also found in Amiga library documentation.
So assuming that you know all about the routine you are calling and its
start-up parameters, you now need to know what to do with the start-up
parameters when calling a library from HeliOS.
HeliOS is very close to assembly language in operation, so it handles
library calling parameters in a manner closely reflecting the way it is
done in assembly language.
If you look at the Amiga library documentation you will see that there are
instructions for assembly language library calls, telling the programmer in
which 680xx microprocessor registers to store parameters.
You can gather from this that in assembly language you store parameters
directly into the registers within the 680xx microprocessor before calling
a library. The results of library calls are also stored in these 680xx
registers when the library call has been completed.
Don't worry if this sounds difficult - it is actually very easy!
The 680xx has a set of 8 ADDRESS registers, labelled A0-A7, and a set of
8 DATA registers, labelled D0-D7. These registers are all 32-bit registers.
Your library documentation will say things like
Put Buffer Address into register A0
Put Buffer Length into register D0
Call Library
Read result of call from register D0
To translate this type of operation into HeliOS is very easy because
you have a set of DUMMY REGISTERS in which to store your parameters and
read your results.
The DUMMY ADDRESS REGISTERS are accessed as double number 32-bit variables
by putting the register number you require on the HeliOS stack and then
using the word AREG to return the variable address.
The same method applies to DUMMY DATA REGISTERS but this time you use the
word DREG.
When HeliOS calls a library for you, using the HeliOS Word LIBRARY,
it simply unloads the dummy registers into the actual 680xx processor
registers, calls the library, then unloads the 680xx registers back into
the dummy registers. This is very useful because it means that the values
in the dummy registers are retained for your use until the next time you
make a library call.
To carry out the example library call given above you would:
Put Buffer Address into DUMMY register A0
Put Buffer Length into DUMMY register D0
Call Library
Read result of call from DUMMY register D0
To do this in Helios code you might write:
BUFFERADDRESS D@ \ Get buffer address onto stack
0 AREG D! \ Store it in DUMMY ADDRESS REGISTER A0
BUFFERLENGTH D@ \ Get buffer length onto stack
0 DREG D! \ Store it in DUMMY DATA REGISTER D0
LIBRARYBASE \ Put address of Library base store onto stack
-64 \ Get library offset onto stack
LIBRARY \ Call library
0 DREG D@ \ Get result from DUMMY DATA REGISTER D0 onto stack
Remember, the dummy registers will always directly reflect their 680xx
counterparts before and after the library call.
The word LIBRARY which makes the call is not at all complicated, you simply
put the name of the variable where the library base address is stored onto
the stack, followed by the library routine offset, then use the word
LIBRARY exactly as shown above.
Note that it is not the library base pointer itself that is used by the
word "LIBRARY" but the 16-bit storage variable address.
That is all there is to calling Amiga libraries, except for one thing which
makes it even easier! In the above code we have accessed the result of the
library call, in register D0, quite correctly using "0 DREG D@". Because
this sequence is used very often we have included an easy and quicker single
word alternative. Instead of typing "0 DREG D@" you can simply type the one
word "D0RESULT" to get the value in DUMMY REGISTER D0.
*****************************************************************************
----------------------------------------------------
General procedures for Starting and Closing programs
----------------------------------------------------
It is a good idea to stick to a regular procedure (hopefully a good one)
when writing all your programs. Especially in code which starts and closes
down your programs, it is possible and desirable to use a standard set of
prewritten subroutines which can be modified as required.
There are several rules that you should follow to produce good, safe code-
1. Always mirror opening and closing calls.
2. Always have ONE universal and thorough exit point.
3. Always make sure you close down everything you open, especially memory.
4. Always initialise variables correctly.
5. Always check memory available before and after using a program
- if you are losing memory something is very wrong.
6. Always arrange your own output screen/window for serious programs
- you can't use the interactive HeliOS window in stand-alone compiled
code......because it won't be there!
It is a good idea to use two standard start-up and close-down words for all
your programs. Any special functions needed to start particular programs may
be handled as single extra subroutine calls rather than all the code being
included directly in your main startup subroutine.
We include below simple source code for a program which:
Has a simple structured "startup" word definition and a corresponding
"closedown" routine. You can modify these for your own purposes and it
would be a good idea to use them as a basis for all your early programs.
Opens a custom screen
Opens a window on the new screen
Sets up graphic output to the new window and draws some graphics,
including "graphic text"
Sets up console text output in the new window and prints some text
Sets up user input from the new window and waits for <SPACE> to
be pressed.
Uses an Amiga library call to show how it is done.
Uses most of the things we have been discussing above......
You will be surprised, perhaps, to see how easy all this is, and certainly
you will be amazed how easy it is if you have used other Amiga programming
languages which require you to do an enormous amount more preparatory work.
Note:
The following program is provided as a disk file called "TutorialProg.Src".
Load this program into the HeliOS editor, as described for the small
tutorial programs given earlier, then compile and run it.
A typical start up program section might be as follows-
FORGET **CORE** \ Clear the user dictionary
D0 DVARIABLE SCREEN \ New Screen handle storage variable
D0 DVARIABLE WINDOW \ Window handle store
D0 DVARIABLE BITMAP \ Variables to store useful values, which.
D0 DVARIABLE RASTPORT \ are collected at startup time in case of
D0 DVARIABLE VIEW \ the need to use them later in graphics
D0 DVARIABLE VIEWPORT \ related functions.
\ OPENSYSTEM - Opens a screen and a window and sets up Input/Output.
\ Includes an example of a library call for you to see
\ Returns "1" on the stack for success and "0" for failure
: OPENSYSTEM \ Start a colon definition, the new word is
\ called, appropriately, "OPENSYSTEM"
TIMEOFF \ Disable the time display in the HeliOS screen
0 HISTORY \ Disable the line editor's circular buffer
1 BAKSET \ Enable creation of Backup files on all disk
\ SAVE operations - a useful safety feature
\ These are all "general purpose" startup operations often used
1 STDSCREEN \ Initialises a standard NewScreen structure
\ and sets Hires mode
LIT$ $Tutorial Screen$ \ Specify the screen title bar text
640 250 \ Specify screen width and height
3 \ Depth of screen = number of bit planes
OPENSCREEN \ Open a screen using the initialised structure
SCREEN D! \ Store the screen handle/pointer
SCREEN D@ \ Get SCREEN 32-bit pointer onto stack
D0> \ Test if SCREEN is greater than zero
\ This checks to see if screen opened OK
\ If SCREEN is zero we have trouble.......
IF \ If SCREEN is not zero we are OK.........
SCREEN D@ \ Get 32-bit pointer to screen
44. \ Put double length number 44 on stack
D+ \ Add this to screen pointer to give
\ ViewPort pointer
VIEWPORT D! \ Store the ViewPort for the new screen
STDWINDOW \ Initialise a standard NewWindow structure
HFWINDOW \ Modify the standard window for it to appear
\ on the HeliOS Screen
SCREEN D@ \ Get new screen again
WINDOWSTRUCT \ Returns 16-bit pointer to NewWindow
30 + \ Add 30 to this
D! \ Store screen pointer into NewWindow structure
LIT$ $Tutorial Window$ \ Title bar text for window
0 12 640 238 \ Guess what....Window dimensions!
3 \ 3 BitPlanes
0 \ No SUPERBITMAP
OPENWINDOW \ Open the new window
WINDOW D! \ and store window pointer/handle
WINDOW D@ \ Check if opened OK, like screen above
D0> \ See "screen open" check above........
IF
WINDOW D@
MAKEGFXWINDOW \ Enable graphics in this window
WINDOW D@
MAKEOUTWINDOW \ Enable text output to this window
WINDOW D@
MAKEINWINDOW \ Enable user input from this window
WINDOW D@ \ Get Window pointer
50. D+ \ Add 50 to Window Pointer to get RastPort
D@L \ Get RASTPORT pointer
RASTPORT D! \ Get Window's RastPort, and store it in
\ variable RASTPORT
RASTPORT D@
4. D+ D@L
BITMAP D! \ Get the bitmap from the stored RastPort
INTUBASE \ Put on the stack the 16-bit address
\ where the 32-bit pointer to Intuition
\ library base is stored
-294 \ Put on the stack the offset of the library
\ call "ViewAddress"
LIBRARY \ Call Intuition Library function to get
\ VIEW pointer
D0RESULT \ Get dummy register D0 value which is the
\ View address returned from the library call
VIEW D! \ Store pointer in variable VIEW
1 \ Put value "1" on stack to indicate that
\ everything opened OK
ELSE
0 \ Put "0" on stack to indicate failure
THEN
ELSE
0 \ Put "0" on stack to indicate failure
THEN
; \ End of Colon Definition
\ In a similar manner we have a defined a HeliOS word for the related
\ close down routine -
: CLOSESYSTEM \ Start the colon definition
FORTHINWINDOW \ Redirect the input and output from
FORTHOUTWINDOW \ program's window back to the HeliOS
FWINDOW MAKEGFXWINDOW \ interactive environment
WINDOW D@ \ Get contents of window handle store
DFLAG \ Check and if Non-Zero put 1 on stack else
\ put 0 on stack above window handle
IF \ If window is open, ie handle is non zero
CLOSEWINDOW \ Close it
WINDOW D0! \ then set store to zero
ELSE
DDROP \ else cleanup stack (drop window handle)
THEN \ end of If/Then structure
SCREEN D@ \ Look at screen handle
DFLAG IF \ If it is open......
CLOSESCREEN
SCREEN D0!
ELSE
DDROP
THEN
TIMEON \ Enable time display for the
\ HeliOS screen before exiting
; \ End of colon definition
\ Now we can use these functions in a small program:
: TUTORIALPROGRAM
OPENSYSTEM \ Open environment, returning 1 or 0
\ indicating success or failure
IF \ If 1 is returned, for "success"
1 GFXSETOPEN \ Set graphics outline pen colour to 1
1 GFXOUTLINE \ Switch on graphics OUTLINE mode
2 GFXSETAPEN \ Set graphics pen to "2" for circle
400 160 80 40 \ Circle coordinates
GFXAREAELLIPSE \ Draw circle into off screen buffer
GFXAREAEND \ Render circle to screen
0 GFXOUTLINE \ Switch off graphics OUTLINE mode
3 GFXSETAPEN \ Set graphics pen to "3" for text
100 200 GFXMOVE \ Set graphics pen position
LIT$ $This is graphic text$ \ Text string
COUNT \ Get text start and length
GFXTEXT \ Output text
20 10 CURPUT \ Place cursor
." Hello....Press <SPACE> to exit!" \ Some console text output
BEGIN \ Start a BEGIN/UNTIL construct
KEY \ Wait for a keypress
32 \ ASCII code for <SPACE> is 32
= \ See if KEY value = 32
UNTIL \ Loop until result is TRUE
THEN
CLOSESYSTEM \ Close environment
;
TUTORIALPROGRAM \ Actually execute the new "program" word.
\ End of program
*************************************************************************
-------------------------------
A few simple hints on debugging
-------------------------------
HeliOS has a very powerful user-configurable debugger, but for most
debugging you should never need to use it! The following hints should
be taken as general programming guidelines, and for detailed discussion
of the HeliOS debugger you should refer to the debugger documentation.
There are a few simple techniques which, combined with sensible programming
strategies (for example, do not write 200k of source code altogether with
no testing then expect it to work instantly...), will enable you to debug
code very simply.
When a bug occurs the program will often (probably!) crash.
The best simple debugging technique is to put a repetitive debug line
into the code up to and including the crash point.
This line should display the stack status and wait for the space bar
to be pressed. Something like the following will do nicely:
." Now at line xxx. Stack reads: " .S ." <SPACE> to continue" WAITSPACE CR
A few of these lines included in your code will give you a sequential
talk-through until the crash point is reached.
Start with the high level code first and then work into your subroutines:
in this way you can home in on the actual fault. It is good practice to
check each subroutine thoroughly as it is completed, but nevertheless the
most unexpected results can occur when even apparantly sound subroutines
are used together in complex ways.
The stack status message debug line suggested above will probably mess up
your program's screen display, but that does not really matter in a debug
operation.
Always check for stack aberrations first. Be aware of what the stack should
be reading and check your debug stack readouts scrupulously.
If you like, include DUMP commands in your debug instructions to dump areas
of memory for careful scrutiny.
There are so many ways for code to fail it is impossible to cover all the
aspects of debugging. Also debugging is a very intuitive thing and everyone
has very personal preferences.
The main thing is to never assume ANYTHING to be OK without double checking,
and be prepared to be patient and check EVERYTHING relating to your problem
with an open mind.
Check your stack dumps minutely, dump and also check any areas of memory
you think may be suspect, check variable values by including them in your
debug lines where appropriate.
One big source of trouble is using address pointers which should really be
pointing at something useful like a screen structure address, but actually
contain zero. For example, in our little program above, we checked that
the screen had opened OK and that its returned value was not null. If we
did not do this and then went on to use the screen handle, not realising
that it was zero, terrible things would happen.....
This sort of mistake is quite easy to make in more complex code, and can
be very nasty. A golden rule on a multitasking machine like the Amiga
is never to assume that an allocation or opening routine must always
succeed. Always check to see if everything has opened correctly, and
always take care to initialise all fields of data structures correctly.
*************************************************************************
-------------------
Additional reading?
-------------------
Perhaps you are wondering whether HeliOS is similar to any other languages
and whether you can get any books to help you learn to program?
It is always useful to read a variety of documentary material when you are
learning a new programming language because different authors will often
give you very different and valuable insights.
HeliOS is a threaded interpretive language derived from Forth, so many
of its simplest commands are Forth oriented. A basic understanding of
Forth (which is a much smaller language in scope than HeliOS) will
certainly help you get started with HeliOS, and if you have access to
any Forth textbooks these will give you a good idea of the way HeliOS
programs are structured.
HeliOS uses a stack for much of its parameter passing, as well as using
reverse polish notation like Forth, so you will certainly benefit by
reading about these concepts in any of the excellent Forth texbooks
available. Forth text books will provide you with many helpful insights
if you want to read them as background information: however, you should
beware of taking the analogy between Forth and HeliOS too far. The fact
is that the similarity between the languages is superficial and sometimes
deceptive, so take care not to learn false ideas.
As a Forth instructional text we advise you to purchase Leo Brodie's
excellent text "Starting Forth", published by Prentice Hall in paperback.
You will certainly need to study specialised texts on the Amiga if you
want to get the best out of HeliOS because HeliOS, like "C", makes use of
the Amiga operating system and also allows direct Amiga hardware control.
The Addison-Wesley Amiga manuals are an excellent investment if you are
serious about Amiga programming, and Compute Books' "Mapping the Amiga"
is an extremely useful reference text.
HeliOS can supply an excellent comprehensive set of example programs on
all HeliOS commands written by Sebastien Veyrin-Forrer. These short
example programs detail the use of every word in the HeliOS vocabulary.
----------------------------------------------------------------------
End
----------------------------------------------------------------------