Topics covered in this tutorial: * Looking forward and getting started * How HeliOS differs from other computer languages * Controlling the Amiga with HeliOS * A first HeliOS program * Rules for creating new command words * Simple programming strategy * Order of creation of HeliOS commands * Organisation and structure * Using IF...ELSE...THEN constructs in conditional statements * Combining flags * Functions, Data and Error Checking * The HeliOS vocabulary, the dictionary, and the compilation process * The concepts of RUN-TIME and COMPILE-TIME * Creating standalone HeliOS programs * The HeliOS Stack ----------------------------------- Looking forward and getting started ----------------------------------- These introductory tutorials are intended to explain a few general ideas which may help you get started with HeliOS. Because simple once-only statements of fact are not really the best way of introducing a complex subject, we have provided a series of tutorials which in some respects cover similar ground in different ways, thus emphasising important information and gradually broadening the scope of the examples. In particular, the first two tutorials both approach the first steps in HeliOS programming from slightly different angles, with many basic concepts reiterated for emphasis. 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. Anyway, if you come across something you feel that you already know in the tutorials, please do continue reading unless you already are very confident of your understanding, because there may be some new ideas in here..... ------------------------------------------------ How HeliOS differs from other computer languages ------------------------------------------------ Before explaining the fundamentals of HeliOS programming it is worthwhile looking briefly at the differences between computer programming languages. This is important because HeliOS is probably very different from any other languages with which you may be familiar and may well open up many novel possibilities which you had not previously considered. If you are already experienced with a computer language such as BASIC or PASCAL, you will need to forget many of the restrictions imposed by such languages. HeliOS is a fluid, redefinable, very linguistically oriented language, with much greater freedom of expression and very different "free form" programming style. If you are already familiar with assembly language you will, in some ways, be more instantly at home with HeliOS, because it allows direct control of data storage in memory in a similar fashion to assembly language. In fact, HeliOS allows the integration of assembly language directly within high level HeliOS code, and HeliOS has many functions which are very close to assembly language in concept. HeliOS is also close to assembly language in potential speed and efficiency. If you are new to programming, you will find that HeliOS will be rather more easy to learn than some of the more restrictive and old fashioned computer languages such as BASIC. Coming fresh to HeliOS with no preconceptions, you will perhaps be better placed even than already experienced programmers to take advantage of all the novel new concepts found in HeliOS. Since HeliOS as so different from other computer languages, let us assume that you are new to programming and take things from the beginning. Your first task is to learn a few simple and fundamental aspects of general communication with your computer: think of it as learning to converse with someone who does not speak your own native language. You will have to learn a new mode of communication, and interestingly you can also adapt HeliOS to use a form of linguistic expression chosen by you. Unlike most other computer languages HeliOS is an EXTENSIBLE language, so you can literally program by extending the actual set of words you use to communicate with the computer: you effectively build your own dialect of the language as you go. In a sense you could say that HeliOS allows you to train the computer to speak YOUR personal language. This is quite an advanced capability which allows HeliOS programmers to develop a high degree of personal style and creativity. Using HeliOS you can actually build a unique language which ideally suits your own style of programming, and which interfaces to the Amiga in the most efficient possible way. HeliOS allows you to create new commands based on your own ideas and incorporating programming methods which you prefer. Notice how much emphasis is being placed upon "communication" and the use of "language": this is very important, because HeliOS is really about inventing your own communication channel with the Amiga, based upon a mutual use of a shared vocabulary which YOU specify. You could almost say that HeliOS is a verbally or semantically oriented language, rather than a simple number manipulating or "computational" language. Already, if you are a BASIC or "C" programmer, you will perhaps be slightly intrigued by what is a whole new world of programming possibilities. Of course there are many computer languages, all of which have strengths and weaknesses, and also the computer which you use will include its own set of individual features. Your task is really twofold: to master an effective means of communication and then to learn how to control all the different functions of the particular machine with which you are working. Your choice of computer determines the final results which you can achieve, and some computers are better at certain tasks than others. The Amiga is possibly the most versatile home computer of all, so you will certainly have many interesting avenues to explore. Your choice of language will very much influence the ease and productivity of the task of programming, and your chosen language might be assessed in terms of two really vital measures of performance: 1. Is the language capable of flexible control of ALL aspects of your computer, or is it going to be incapable of performing certain tasks. For example, most high level languages lack speed, and are therefore less capable than assembly language when it comes to creating games. If you want to write game software without having to resort to assembly language you need to choose a very fast high level language. 2. Is the language flexible and easy to use from YOUR point of view. For example, ideally you need a language which makes it easy to do the kinds of things you want to do with the computer. You also need to be comfortable with the general interface between you and the language in terms of editing source code and program testing. Computer languages vary in speed and power: most languages are called "high level" languages because they insulate you from dealing with "low level" technicalities to do with the actual operation of the computer hardware. These languages usually have a certain trade-off of speed and flexibility in favour of simplicity of use: they are biased towards making life easy for the programmer rather than being computer-efficient. At the other end of the programming language scale is assembly language, which deals directly with the computer hardware and requires the human programmer to adapt to the needs of the machine rather than vice-versa. Assembly language is the most powerful language in terms of speed and efficiency, but it is quite difficult and unforgiving from the point of view of the programmer. Another broad difference between languages is whether they are "compilers" or "interpreters". A "compiler" has to first pre-process a complete set of program instructions and prepare an executable file which then has to be run to test the program. This can be a slow and tedious process, and makes the task of the beginner so much harder because there is no facility for easy instant testing of small code fragments. An "interpreter" on the other hand, allows you to type in a command and get an instant response: the language can instantly interpret what you type. This is excellent for beginners, because it is easy to test small sections of code and experiment to get things working correctly. Traditionally interpreters were slow languages because all the program instructions were literally being interpreted as the program ran. In recent times interpretive languages have often been equipped with add-on compilers which process the final program source code into an "executable" form which runs faster because it has been "pre-interpreted". Most more modern and efficient languages are pure compilers, and the special advantages of interpretive languages are no longer available to users of such languages. So, being unrealistic and hopeful, ideally you might be looking for an easy to learn high level language, which is capable of assembly language speed, full direct computer hardware control if required, and which has the best features of both a compiler and an interpreter! You might think that this is an impossible dream..... Certainly this requirement eliminiates virtually all languages available for the Amiga, but HeliOS actually does fulfill all these functions! HeliOS is a very flexible interpreter AND compiler: a high level language with a natural speed nearly equivalent to assembly language. HeliOS has a full capacity to control the computer hardware directly, and can even allow pure assembly language to be written within high level code. Best of all, HeliOS has the most sophisticated and comfortable "human interface" of ANY language, so its powerful programming tools are available in an enjoyable and easily approachable form. HeliOS will easily allow you to exploit every facility of the Amiga, but do not try to rush into doing complicated things too early. The Amiga itself is very complex and sophisticated, and no matter how easily HeliOS allows you to write programs, you must take care to learn how the Amiga functions in detail before you can effectively control the computer. This tutorial will teach you how to work with HeliOS, and you will soon learn to work with the Amiga operating system and hardware: then you will be free to create the most ambitious programs you can imagine. However, that is for the future, and for now we will look at some simple ways to get to know the HeliOS language. --------------------------------- Controlling the Amiga with HeliOS --------------------------------- How does a computer language allow you to control a computer? How do YOU control your chosen computer language? In fact......just how does a simple digital machine manage to "come alive" and produce the fascinating sounds and graphical extravaganzas which we often see in Amiga software? It does so, largely, by your creative input, and to provide this you need tools to enable you to express yourself using this new creative medium. You then need to learn to use these tools constructively and confidently, so that you can turn the computer into an instrument for expressing your own ideas effectively. HeliOS provides you with an excellent toolkit, but if you don't master the fundamentals well, as in any artistic pursuit, the computer and the language will impose themselves on you to the point that you are forced to tread a tedious tightrope of obediance to rigid rules. HeliOS gives you hundreds of different ways to do any job: the choice is yours, so learn how to use this range of choice for your own creative ends. If you want to be in control and have choices on how to perform a certain programming task, you need to have a good general idea of how the computer works and a sound understanding of the fundamental operation of your chosen computer language. Even though it takes time and experience to accumulate full understanding of these matters, you should try from the start to learn as much as possible about the technical background within which framework your programs function. You will gain experience and detailed knowledge quite easily and painlessly as you progress, and initially incomprehensible technical details will soon fall into place if you persevere. Eventually, when you come to write more complex software, there is no doubt that you will have to do some learning about Amiga-specific technicalities, but first of all you need an overview of the programming process and a few simple ground rules to get you started with HeliOS. If you follow the simple tutorial exercises and grasp fundamental HeliOS programming practises, you will be able to enjoy rewarding results from even your first day of HeliOS programming, without needing too much Amiga technical knowledge. HeliOS has many simple commands which will help you to easily control quite complex Amiga functions, and using these simple pre-programmed commands as a starting point you will soon be able to write all kinds of interesting and useful software. The Amiga computer has many functional sub-systems which can be likened to groups of people with various talents, each of whom uses a specific linguistic "dialect" designed to express concepts related to their task. It will be your job as a programmer to communicate with all these "people", each in their own idiom, and you will need to develop tools and methods with which to express your instructions. For example, you would need one type of knowledge and technique for writing a sound synthesizer program, and you would need another for writing a graphics-intensive arcade game. An ideal computer language is an "interface" consisting of pre-designed commands which are comprehensible to the programmer and which are also adaptable to meet the demands of communicating with every aspect of the host computer. HeliOS has many specialised commands to help you deal with specific functions of the Amiga, and is probably the closest thing to a total Amiga control language which you will find. Any programming language presents one face to you and another face to the machine: this is its job. The less work that has to be done "in between", in forcing your commands into direct machine instructions, the better and more efficient will be the result. HeliOS itself imposes a minimum of its own character and allows you to control all aspects of the Amiga very directly, in the way in which you choose. Most programming languages have developed over years into fairly rigid and limited systems which are not ideally adaptable to all aspects of controlling modern computers. This tends to mean that a language has a very formal structure, and in fact many languages are only good at certain particular tasks. HeliOS takes a different approach and allows you build your own language for any programming requirement: HeliOS allows you, the programmer, to recreate the language itself for any particular task you need to do. In fact it is true to say that as well as being a language in its own right, HeliOS might also be regarded as a sophisticated set of tools for creating new computer languages. In HeliOS, if you want to carry out a complex task, you first have to break down the task into sensible small units, then you EXTEND the language by CREATING new commands to do the particular things you require. Your new commands are named however YOU choose, so they instantly make sense to you and you remember them easily. In other languages you are required always to remember fixed commands written by someone else, and to conform to rigidly inflexible command sets. HeliOS, in short, provides you with a flexible and open ended way of developing your knowledge of the Amiga and your power to control it. ---------------------- A first HeliOS program ---------------------- Let us take, as a first HeliOS programming task, the traditional computer language introductory program: getting the computer to say "Hello World!". To do this in "C" you would need to write quite a lot of code to create a stand-alone program which would first need to set up the capacity for the computer to display a screen and to display text on this screen. In HeliOS, even to write a "stand alone" program to do this would only be a matter of a few words: you could actually do it in one line of code! However, HeliOS includes an "Interpreter" which already has a text display ready for use, so for a simple example all you need to do is switch to the HeliOS Interpreter screen and type your commands directly. Like BASIC, HeliOS has simple commands to output text, but unlike BASIC HeliOS also has a very wide range of more sophisticated and powerful text commands to do many special operations. However, for now, all we need use is a very simple text output function, and this can be done in HeliOS using the expression: ." Hello World!" Let us examine this simple expression, and firstly we can look at the initial two-character word at the start: ." The first part, the . character, is used by HeliOS to indicate that something is being output: it is roughly equivalent to a shorthand form of the word "print". The second part, the " character, is used to indicate that this "double quote mark" will be used to "delimit", or "enclose" the text we want to print. This expression as a whole is saying, in a cryptic form, "print the text following enclosed by double quote marks to the screen". In computer parlance we have a special name for the double quote character used to indicate the start and end of our text message: we call this a DELIMITER, because it "delimits" a text message surrounded by other words which have a different function. Notice that we have emphasised the need to "enclose" text messages within delimiters: we cannot simply say: Hello World! or even ." Hello World! without the final quotation mark. This is important! When you are telling the computer to do something with text you need to be able to define where the text starts and stops, so that the computer can tell the difference between COMMAND words and the actual words of your embedded TEXT message. To understand this, imagine that you had typed a set of commands at the Interpreter command line, and that one of these commands was an instruction to print some text to the screen. You might have something like this: COMMAND1 COMMAND2 ." This is my text to print" COMMAND3 COMMAND4 etc. ^ ^ First delimiter Second delimiter = START of text = END of text You can see how the two " characters are used to enclose and distinguish the embedded text message from the commands before and after them. This concept of "delimiters" is one you will meet often when using text embedded within program code. Let us go back now to our "Hello World!" program: ." Hello World!" If you type this at the HeliOS command line, the Amiga will output the text message "Hello World!". It is as simple as that, so why not try it now..... Here you have typed in one single direct command, but you can of course type in a sequence of commands to do something a little more complicated. Try typing the following (actually, you do not need to retype every word, just press "up-arrow" to recall your previous line of text and then edit the line as required): SCRCLR ." Hello World!" WAITSPACE This will do three different things, one after the other: 1. Clear the text screen 2. Print "Hello World!" 3. Wait for you to press space. Note that all computer programs are essentially simple linear sequences of operations, because the computer can actually only perform one function at any one time. Now try typing the following: SCRCLR 12 12 CURPUT ." Hello World!" WAITSPACE This will set the text cursor position at "column 12, row 12" on the text screen before printing your message. You have already written a short HeliOS program, but it is not very convenient to keep typing all this in at the command line every time. We are now going to create a new single word command which will become a part of the HeliOS vocabulary. This single word will the carry out all the commands in your small new program: effectively you are writing the program for a new HeliOS command word. To create a new HeliOS command word we use two HeliOS functions expressed by use of the colon and semi-colon characters. The colon character tells HeliOS that the next word will be the name of a new command, followed by a command definition. The semi-colon character tells HeliOS that the new command definition is finished. Let us create a new word called HELLO. : HELLO SCRCLR 12 12 CURPUT ." Hello World!" WAITSPACE ; ^ ^^^^^ <-----------------------------------------------> ^ Start Name Definition End This has created a new word called HELLO. Try entering this command line and then displaying the USER vocablulary. You will see your new word HELLO listed as a HeliOS command word: you have already extended the HeliOS language and written a small program. Now try typing just the word HELLO at the command line and press . You will see that your new word does exactly what the original set of commands did when typed in individually: you have just extended the HeliOS language with a new command named and designed to your own specification. ------------------------------------ Rules for creating new command words ------------------------------------ Here, then, are the simple rules for creating new HeliOS command words: 1. Place a "colon" (":") symbol with at least one space on each side. 2. Put your new command name, followed by at least one space. 3. Put your list of "internal" commands with spaces separating them. 4. Place a "semicolon" (";") symbol with at least one space on each side. We refer to a word definition such as this as a "colon definition". Note that the colon definition can occupy as many lines as you like: there is no limit on its size and complexity. This process of creating new commands is exactly what you do when writing all HeliOS programs: you keep on extending the language with ever more powerful commands, until you finally have one "master" command which uses all your previous constructions to carry out the main program. Let us now make another command, called "PRINT_RED". : PRINT_RED 6 FPENSET ; This command sets the text colour to "colour 6", which will be RED unless you have changed your HeliOS colours. You can now say: PRINT_RED HELLO Getting more ambitious, we can make another new word: : PRINT_RED_HELLO PRINT_RED HELLO ; This is a compound word made up from our previous new commands, and you will see that HeliOS can freely mix any combination of your new words with its own CORE command set. Remember: * There is no essential difference between HeliOS CORE functions and the command words which you create yourself using colon definitions. Can you see what the following expression does? : PRINT_BOLD_RED_HELLO BOLDON PRINT_RED_HELLO ; Try it! And this.... : FANCYHELLO 7 BPENSET PRINT_BOLD_RED_HELLO 2 BPENSET SCRCLR ; The process of building new HeliOS commands should now be quite clear. When you come to write a "real" program of course, you will not be using the command lines: you will be writing programs as text (or "source code") in an editor. Many computer languages require source code to be written in a very strict format, but HeliOS is totally relaxed in its source code format, allowing you to choose a style which suits your own preference. It is a good idea to use plenty of "white space" so that your programs are not cluttered and confusing, and it is best to make use of separate lines for distinct command sequences. Look at this example of how you might turn all the above commands into a short HeliOS program in a text editor: : HELLO SCRCLR 12 12 CURPUT ." Hello World!" WAITSPACE ; : PRINT_RED 6 FPENSET ; : PRINT_RED_HELLO PRINT_RED HELLO ; : PRINT_BOLD_RED_HELLO BOLDON PRINT_RED_HELLO ; : FANCYHELLO 7 BPENSET PRINT_BOLD_RED_HELLO 2 BPENSET SCRCLR ; We have used UPPER CASE characters throughout, but you do not need to do so. You could equally well have written FANCYHELLO as: : FancyHello 7 BPenSet Print_Bold_Red_Hello 2 BPenSet ScrClr ; or even: : FancyHello 7 BPenSet Print_Bold_Red_Hello 2 BPenSet ScrClr ; This last option is actually quite a BAD idea, and with a little thought we can see why. It is always best to use the sequence of vertically spaced short lines within your source code to help express the sequential logic of the program. Keeping each short section of the program on a separate line makes it easy to follow what the program is doing and also leaves space to add comments on individual operations as required. The layout of your source code can, and should, help you comprehend the structure of your program. It is very useful in many cases to add notes to your programs, explaining what is happening at each stage. This is called "commenting", and the addition of "comments" is vitally important once you start writing big complicated programs. You may understand what a program is doing when you write it, but you will surely forget details when you return to it after some time has elapsed. It is often very useful to add comments to each line, like this: : FancyHello \ Print red and yellow "Hello" message 7 BPenSet \ Set background to "yellow" Print_Bold_Red_Hello \ Clear display and print message 2 BPenSet \ Reset background to white ScrClr \ Clear display ; Notice that we use the "\" character to inform HeliOS that all text on the rest of that line is a comment. HeliOS source code can also include longer multi-line comments. You do this by enclosing the long text comment in brackets, like this: HELLO ( This is a long text comment, which can go on and on for as many lines as I like. I can carry on writing and HeliOS will ignore all this until it finds a final ")" character with spaces on each side of it, upon which it will carry on interpreting the program. ) FANCYHELLO Perhaps you might have noticed something quite subtle: there was another ")" bracket character WITHIN the comment which somehow HeliOS was clever enough to ignore. How do you think HeliOS knew which bracket to use to determine the end of the comment? The answer to this brings us to an important rule: * ALL HELIOS COMMAND WORDS MUST BE DELIMITED BY SPACES This is very natural really, since it is just how we ourselves communicate. After all, look what happens if we remove spaces from the line above: Thisisverynaturalreally,sinceitisjusthowweourselvescommunicate. HeliOS, like any normal person, requires its communications to be separated by spaces, and because this is such a natural consideration, it is quite unlikely that you will make the mistake of forgetting it. However, if you do miss out a space between two words, HeliOS will merely tell you that it cannot understand and point out to you where it lost track of what you were saying. Try typing this at the command line: : FancyHello 7BPenSet Print_Bold_Red_Hello 2 BPenSet ScrClr ; ^^ Missing space You can see that HeliOS is really quite helpful, and pointed out where you had gone wrong without any untoward problems. Going back to the case of the bracket within the comment, and indeed to comment markers in general, you should always remember that after the first bracket (which must have surrounding spaces) HeliOS will regard everything as a comment until it finds a final bracket with surrounding spaces. If you were to place a ) character surrounded by spaces WITHIN your comment, HeliOS would assume that you wanted the comment to end there. You should also take care not to write a line like this: 7 BPenSet \Set background to "yellow" ^^ No space If you miss out the space, HeliOS will not understand that you are writing a comment. Try it and see...... One final point will lead us to the conclusion of this first lesson. Perhaps you have noticed already that HeliOS will allow you to make several new definitions of the same command. In this case HeliOS warns you that you have made multiple definitions, but will accept the new command on top of the previous ones. Notice that the latest verson defined will be the one which is performed when you subsequently type the command name. We will discuss this in more detail elsewhere, but for now we might point out that if you want to clear all old command definitions you simply type: FORGET **CORE** This will cause HeliOS to "forget" all the new commands it has learned, and revert to its own in-built set of CORE functions. Notice that once again HeliOS behaves in a fairly "human" way compared with most computer languages: you teach it new words and use them in expressive ways similar to our own use of language, then you tell it to "forget". *************************************************************************** --------------------------- Simple programming strategy --------------------------- We can now go on to a slightly more complex example, and in doing so we will look at simple ways of designing programs more efficiently. Let us say that we want to print to the screen our name and address. If we asked a person to do this type of task, we would assume that they knew how to write, how to use a pen, etc. etc., and we would be able to give them one simple command to do the job. A computer on the other hand always has to be told explicitly what to do at each stage of the process. The art of writing good computer software lies very much in developing a skillful understanding of how to break down complex tasks into several simple ones. A good programmer can reduce a complex task to a relatively "intuitive" set of economical functions, whereas a less skilled programmer would probably write twice as much code to do the same job in a clumsy way. All programs ultimately resolve down to the use of the "primitive" commands available in the computer language you are using, and you need to become adept at using these commands and skilled in selecting appropriate methods for undertaking particular tasks. HeliOS has very many preset commands to carry out common tasks, and one of the first things you must learn is how to find out information about these standard command words. The list of command words, in HeliOS, is called the DICTIONARY, and you will find that the most important file in the whole of the HeliOS documentation is the "Dictionary.doc" command definition file. You may like to keep a copy of the "Dictionary.doc" file available at all times by loading it into a spare HeliOS editor. Alternatively, you could keep a copy of the file loaded into a separate text viewer program, which could be multitasked alongside HeliOS on its own "pop-up" screen. By the way, the actual current set of available commands is referred to in HeliOS as the VOCABULARY, so you can see from all this "verbal" terminology that this is indeed a very linguistically oriented language. As you write programs you actually add commands of your own to the HeliOS vocabulary, thus effectively building your own personalised version of the language. * Remember here that HeliOS has a Vocabulary Help system which is designed to allow you to set up short on-line help for all your own newly created HeliOS command words. You can make a short Vocabulary Help entry for each new word you create (and for any HeliOS CORE word) so that you then have instant on-line help available by simply placing the cursor over the word and evoking the Vocabulary Help system. Going back to our example, let us assume we want to print this address: Mr. W. Smith 12, Blitter Street AmigaTown ComputerLand Obviously, no computer language comes with a single built-in command which with one simple action will print your name and address at a chosen place on the screen and in chosen text colours and styles. Even this very simple task requires a program to be written to do it, and our first task must be to work out a series of simple sub-commands to tell the computer how get the job done. Then we can create a new master-command, which we might perhaps call "PrintAddress", which performs the whole of our new command program. Let us first make a preliminary list of what sort of things we want this command to do, in the form of a simple very explicit step-by-step sequence: 1. Clear the page of previous text. On a computer, remember, the screen/page is not always empty! 2. Move the pen (or text cursor) to a certain place on the page. Planning ahead, it would be nice to be able to specify this position as a parameter to our new command PrintAddress, allowing us to use the command flexibly to print at at different places on the screen. 3. Set up a text style for the first line of the address (the name) We will not bother with fonts at this stage, but it would be nice to be able to specify text style and colour: for this example perhaps we might use BOLD type in black for the first "name" line. 4. Print our name. 5. Move to the next line immediately below the start of the name. 6. Set up a text style for the second part (the address itself) It would be nice to be able to specify a different text style and colour for the address, and for this example we will use ITALIC type in black for this part of the text. 7. Print the first line of the address. 8. Move to the next line immediately below...... 9. Set text style. We may or may not want to change styles again, but we include this line just in case. 10. Print the second line of the address. 11. Move to the next line immediately below...... 12. Set text style. We may or may not want to change styles again, but we include this line just in case. 13. Print the third line of the address. Notice that we need to break down commands to the computer into very simple sequential operations. We now need to specify descriptive names for all the sequential operations. It is best to always use function names which describe clearly to anyone reading the code (or yourself in time to come) what is happening. Using cryptic and complex looking expressions may make your code look very clever and difficult, but it is not good programming. Do not fall into the trap of using short and meaningless function names: it merely makes your code hard to read and to debug. 1. ClearScreen 2. SetNamePosition 3. SetNameTextStyle 4. PrintName 5. SetAdd1Position 6. SetAdd1TextStyle 7. PrintAddress1 8. SetAdd2Position 9. SetAdd2TextStyle 10. PrintAddress2 11. SetAdd3Position 12. SetAdd3TextStyle 13. PrintAddress3 Having arrived at this stage we can string together these operations into a program sequence which will define our new address print function. Our new mini-program, PrintAddress, will look something like this: : PrintAddress ClearScreen SetNamePosition SetNameTextStyle PrintName SetAdd1Position SetAdd1TextStyle PrintAddress1 SetAdd2Position SetAdd2TextStyle PrintAddress2 SetAdd3Position SetAdd3TextStyle PrintAddress3 ; Notice that this is still just a simple sequential list of commands. You can imagine issuing these commands to a person (perhaps being a little more polite), and then watching the sequential series of commands being performed. It is exactly the same with the computer, which will perform the commands making up the PrintAddress function in simple linear order. Before we start issuing these commands we really ought to think a little to see if we have decided on the best way of doing things. It is all very well instructing people or computers to do things, but it does make a great deal of difference if the commands which we issue are sensible. In the case of people, this makes them much happier to carry out our plans, and with computers we usually get the job done quicker and much more efficiently if we think things out carefully first. Look again at our command list: ClearScreen SetNamePosition SetNameTextStyle PrintName SetAdd1Position * SetAdd1TextStyle + PrintAddress1 SetAdd2Position * SetAdd2TextStyle + PrintAddress2 SetAdd3Position * SetAdd3TextStyle + PrintAddress3 Look at the lines marked with * and +. Now look again at another possible version of this program: 1 ClearScreen 2 SetNamePosition 3 SetNameTextStyle 4 PrintName 5 NextScreenLine * 6 SetAddTextStyle + 7 PrintAddress1 8 NextScreenLine * 9 SetAddTextStyle + 10 PrintAddress2 11 NextScreenLine * 12 SetAddTextStyle + 13 PrintAddress3 Notice that in the new version lines 5, 8, and 11 are all the same command, which we call NextScreenLine, and lines 6, 9 and 12 are also all the same command SetAddTextStyle. This means that we will be able to re-use parts of our program, which will save time and effort: notice that we need less different command words in the new definition. We have managed to do this because we noticed that parts of the task could be described in a way which was repetitive and similar: 1. Setting a new line can be done by just moving down the page by one line. 2. We can use the same address text style for each line of the address. This kind of strategic planning is a very important part of designing all computer software. Now we have reduced the number of DIFFERENT commands we need to create from 13 to 9, but we can go further still: 1 ClearScreen 2 SetNamePosition 3 SetNameTextStyle 4 PrintName 5 NextScreenLine 6 SetAddTextStyle 7 PrintAddress1 8 NextScreenLine 9 PrintAddress2 10 NextScreenLine 11 PrintAddress3 Here we still have 9 different commands, but we have removed the two last instances of "SetAddTextStyle" from our final program. We can do this only because we know that once a text style is set in HeliOS, any further text will continue to be printed in that style. We needed SPECIAL KNOWLEDGE to make this particular economy, and you will find that as you grow in experience you will on many occasions be able to make your programs more economical by "tricks" such as this. We could go on making changes, but let us for now settle on this sequence of commands for our program. : PrintAddress ClearScreen SetNamePosition SetNameTextStyle PrintName NextScreenLine SetAddTextStyle PrintAddress1 NextScreenLine PrintAddress2 NextScreenLine PrintAddress3 ; Remember that we COULD write this as: : PrintAddress ClearScreen SetNamePosition SetNameTextStyle PrintName NextScreenLine SetAddTextStyle PrintAddress1 NextScreenLine PrintAddress2 NextScreenLine PrintAddress3 ; Notice that this looks much more confused and is harder to read. As we said above, because computers are sequential devices operating on one command at a time, it is most useful to write programs with one command per line. Using this method it is usually easier to see what is happening. If all the sub-commands in PrintAddress were HeliOS "CORE" words we could proceed simply to write the program as expressed above. However, looking at our definition of PrintAddress, we can see that HeliOS is going to need to know what we mean by several NEW sub-commands before it can carry out our instructions. For example, we have not yet told HeliOS how to "ClearScreen", etc. If we tried to compile this definition as it stands HeliOS would be unable to understand words such as "ClearScreen" and would register an error. So, we now need to define all our new sub-command words, one at a time. Let us do them in order, with "ClearScreen" first. Look at this: : ClearScreen SCRCLR ; You can see that ClearScreen has been defined as just one HeliOS CORE command called SCRCLR. Actually, we are quite fortunate that HeliOS has this single word SCRCLR to clear a text screen: this means that our first definition is very simple! The definition of ClearScreen above will create a new command word in the HeliOS vocabulary called "ClearScreen", which actually does just the same as SCRCLR. All we have achieved in this case is to make our new name for an existing word, but this is quite legitimate. Whenever we now type "ClearScreen", either at the command line or in a program, HeliOS knows that we are wanting it to clear a text screen using its own command SCRCLR. Actually, you can use this technique to rename any of the CORE HeliOS command words if you like..... Let's now look at our second command: : SetNamePosition ( Column, Row - - - ) CURPUT CURSAVE ; This one is a little more interesting. We here have two HeliOS internal commands which do the job we require: CURPUT will set up the text cursor position and CURSAVE will automatically remember the cursor position for future reference. The HeliOS word CURPUT requires us to tell it where we want the cursor putting, which is quite reasonable, and we do this by simply writing the column and row position values as numbers before the command like this: 20 20 CURPUT This would place the cursor at column 20 row 20. Quite easy! The two numbers required by CURPUT to do its work are called "parameters", and the process of supplying these numbers is called "passing parameters". You will soon see that HeliOS command words can pass parameters between themselves too, with one word passing its result to another, and so on. Notice, if you are already a programmer in other languages, that HeliOS requirs no definitions of "variables" at this stage: you simple place the numerical parameters immediately before the command. In fact, HeliOS uses a "Stack" for much of its parameter passing, and for now we will simply mention that a stack is a general storage place where any parameters can be stored until they are needed later. When a HeliOS word requires parameters (in this case Column and Row), we have a conventional way of expressing this in the form of a diagrammatic representation which we call a "Stack Diagram". The Stack Diagram of any HeliOS word is simply a method of specifying the status of the stack before and after that word executes. This information tells us whether the word requires parameters on the stack before it starts, or leaves parameters on the stack when it is finished. You perhaps noticed this in the definition of SetNamePosition: : SetNamePosition ( Column, Row - - - ) ^^^^^^^^^^^^^^^^^^^^^ Stack Diagram Here is a generalised version of this stack diagram: ( Parameter1, Parameter2 - - - ) This tells us that the command in question takes two parameters and does not itself return any parameters. Look at another general example of a Stack Diagram: ( Parameter1, Parameter2 - - - Parameter3, Parameter4 ) ^ ^ <---> ^ ^ 1st Input 2nd Input Command 1st Result 2nd Result parameter parameter parameter parameter The "- - -" represents the operation of the command, the parameters on the left represent things passed to the command (on the stack) before it operates, and parameters returned by the command are shown on the right. You might have a word which takes two parameters and then returns one parameter itself. For example "+" takes two numbers, adds them, and returns the sum of the two numbers as its result. So, "+" would have the following stack diagram: ( Parameter1, Parameter2 - - - Parameter3 ) or ( Number1, Number2 - - - Result_Of_Addition ) Going back to CURPUT, which takes two "column and row" parameters, we can notice something interesting: by putting CURPUT into our new command word "SetNamePosition", this new word will also require the two column and row parameters just like CURPUT. This is easy to understand, if you realise that when HeliOS interprets the SetNamePosition command, what it actually does is to perform the compiled sub-commands CURPUT and CURSAVE sequentially. HeliOS says to itself "Ah, what do I do for SetNamePosition? First I must perform the CURPUT command, then the CURSAVE command". So, "SetNamePosition" will require the same two parameters as CURPUT (in fact the two input parameters are actually used by CURPUT), and will have the following "Stack Diagram": ( Column, Row - - - ) just like CURPUT. You will see later how this works when you run the program. Let's see how we are getting on with our command list. : PrintAddress ClearScreen - done SetNamePosition - done SetNameTextStyle PrintName NextScreenLine SetAddTextStyle PrintAddress1 NextScreenLine PrintAddress2 NextScreenLine PrintAddress3 ; OK. Now let us make "SetNameTextStyle", something like this: : SetNameTextStyle 1 FPENSET BOLDON ; This time we use two more HeliOS sub-commands to make our new word. The command FPENSET takes one parameter, which defines the colour of the foreground text "pen". In this case we set the text colour to "1", which is BLACK. Can you work out a stack diagram for FPENSET? Here it is: FPENSET ( Pen - - - ) The command BOLDON switches HeliOS text mode to BOLD You can see that SetNameTextStyle does not require any external parameters The next command we need is "PrintName". : PrintName ." Mr. W. Smith" ; This will print the text to the screen in the current text style and colour. Here we use again the previous simple method of including text in your program with the ." command (there are many other more sophisticated ways of doing this, as you will see later). Let's look at our command list again. : PrintAddress ClearScreen - done SetNamePosition - done SetNameTextStyle - done PrintName - done NextScreenLine SetAddTextStyle PrintAddress1 NextScreenLine PrintAddress2 NextScreenLine PrintAddress3 ; Now we need: : NextScreenLine CURSET 1 CURDN CURSAVE ; This time we have three HeliOS commands. CURSET - Restores the first CURSOR position we set. 1 CURDN - Moves the cursor down by one position. CURSAVE - Saves the new cursor position. Notice that we have specially designed this command so that it can be used repetitively. It was this "design feature" which allowed us to use this one command in place of three separate commands in our "first version". The next command, "SetAddTextStyle", is very similar to "SetNameTextStyle". : SetAddTextStyle BOLDOFF ITALON ; BOLDOFF - Switches off BOLD text. ITALON - Switches on ITALIC text. The commands "PrintAddress1" etc. are all very like "PrintName". : PrintAddress1 ." 12, Blitter Street" ; : PrintAddress2 ." AmigaTown" ; : PrintAddress3 ." ComputerLand" ; So, we have now created all the elements of our simple program, so let us collect them all together: \ **************** \ Start of program \ **************** : ClearScreen SCRCLR ; : SetNamePosition CURPUT CURSAVE ; : SetNameTextStyle 1 FPENSET BOLDON ; : PrintName ." Mr. W. Smith" ; : NextScreenLine CURSET 1 CURDN CURSAVE ; : SetAddTextStyle BOLDOFF ITALON ; : PrintAddress1 ." 12, Blitter Street" ; : PrintAddress2 ." AmigaTown" ; : PrintAddress3 ." ComputerLand" ; : PrintAddress ClearScreen SetNamePosition SetNameTextStyle PrintName NextScreenLine SetAddTextStyle PrintAddress1 NextScreenLine PrintAddress2 NextScreenLine PrintAddress3 ; \ ************** \ End of program \ ************** Try compiling the small program above, either by: 1. Highlighting it and pressing Amiga-e 2. Cutting and pasting it into another editor, and running it from there. 3. Typing it in at the command line or another editor. Once you have compiled this code you can do a USER-vocabulary listing and you will see each one of your new commands listed. To see your new program working, type at the command line: 12 12 PrintAddress WAITSPACE ^^ ^^ Cursor position parameters. Note that we have supplied two parameters to PrintAddress, whose stack diagram is as follows: PrintAddress ( Column, Row - - - ) This is an interesting point, because you will remember that we actually needed these two parameters originally to satisfy the requirements of the command word CURPUT. Then we included CURPUT in "SetNamePosition", so we realised that the same two parameters would need to be supplied for this word, so that they could in turn be passed to CURPUT. Actually "SetNamePosition" is the SECOND command in our program sequence, with "ClearScreen" coming first. However, no matter where in the program SetNamePosition comes, it still needs its two parameters supplied on the stack. Once these parameters have been placed on the stack, provided that nothing changes the stack in the interim, any number of commands can be executed before SetNamePosition eventually receives the stacked parameters. So what happens to the two parameters for PrintAddress? Think of it this way: when CURPUT, which is a sub-part of our program, eventually executes, it will need two parameters, which it will pull out of the general storage area we call the stack. As far as CURPUT is concerned, it does not care when or how the parameters got there, and in fact it will fetch the last two numbers stored on the stack no matter whether they are the correct ones or not. In our example the two CURPUT parameters are placed on the stack before the main PrintAddress command is executed, and they remain unused and unaltered on the stack until CURPUT is finally executed within the second sub-command SetNamePosition. It is YOUR job as a programmer to make sure that at the time when CURPUT executes the last (top) two numbers on the stack are the required cursor position parameters. You can place these parameters on the HeliOS stack at any time: in fact you can choose whether to type them in when you run the program, as above, or include them in the program. You COULD do any of these: : PrintAddress : PrintAddress : PrintAddress 12 12 ClearScreen ClearScreen ClearScreen 12 12 SetNamePosition SetNamePosition SetNamePosition 12 12 SetNameTextStyle SetNameTextStyle SetNameTextStyle PrintName PrintName PrintName NextScreenLine NextScreenLine NextScreenLine SetAddTextStyle SetAddTextStyle SetAddTextStyle PrintAddress1 PrintAddress1 PrintAddress1 NextScreenLine NextScreenLine NextScreenLine PrintAddress2 PrintAddress2 PrintAddress2 NextScreenLine NextScreenLine NextScreenLine PrintAddress3 PrintAddress3 PrintAddress3 ; ; ; Can you see why the first two examples are OK but the third one will fail? Yes...the parameters are NOT on the stack when SetNamePosition executes, but are placed there afterwards, which is too late. So, here we have another very important point to remember: * IT IS THE PROGRAMMER'S RESPONSIBILITY ALWAYS TO ENSURE THAT CORRECT PARAMETERS ARE PRESENT ON THE STACK AT ALL TIMES This is called "stack handling", and is an absolutely vital part of your initial learning of HeliOS. HeliOS uses a stack because this is an extremely fast and efficient way of passing parameters between commands. You can actually use named variables, or named constants, as you will soon see, but the stack is fastest and in many ways easiest once you are used to it. We will discuss the stack in depth later, but remember for now that a good HeliOS programmer should always keep a clear idea of just what is "on the stack" at any part of a program. You can easily write yourself stack comments within your source code to help you with this if you like: : PrintAddress \ Stack = Empty 12 12 \ Stack = 12 12 ClearScreen \ Stack = 12 12 SetNamePosition \ Stack = Empty SetNameTextStyle PrintName NextScreenLine SetAddTextStyle PrintAddress1 NextScreenLine PrintAddress2 NextScreenLine PrintAddress3 ; You can also write special lines within your code which halt the program, display the current stack parameters (without changing them) and wait for you to press before continuing. In this way you can easily step through a program sequentially, keeping an eye on the stack as you go to ensure that everything is working how you expected. This is a really useful way if debugging a program which is misbehaving, and you should become familiar with the technique right from the start of your HeliOS programming. Here is the sort of line which you might insert into your code to give you a useful debug/stack report: CR ." Arrived at Position 1, and stack = " .S WAITSPACE CR Notice the use of "CR" (carriage return) to separate the text lines. If you were debugging the program above, and you wished to see what was happening as you stepped through it sequentially, you might do something like this: : PrintAddress CR ." Arrived at Position 1, and stack = " .S WAITSPACE CR ClearScreen CR ." Arrived at Position 2, and stack = " .S WAITSPACE CR SetNamePosition CR ." Arrived at Position 3, and stack = " .S WAITSPACE CR SetNameTextStyle CR ." Arrived at Position 4, and stack = " .S WAITSPACE CR PrintName CR ." Arrived at Position 5, and stack = " .S WAITSPACE CR NextScreenLine CR ." Arrived at Position 6, and stack = " .S WAITSPACE CR SetAddTextStyle CR ." Arrived at Position 7, and stack = " .S WAITSPACE CR PrintAddress1 CR ." Arrived at Position 8, and stack = " .S WAITSPACE CR NextScreenLine CR ." Arrived at Position 9, and stack = " .S WAITSPACE CR PrintAddress2 CR ." Arrived at Position 10, and stack = " .S WAITSPACE CR NextScreenLine CR ." Arrived at Position 11, and stack = " .S WAITSPACE CR PrintAddress3 CR ." Arrived at Position 12, and stack = " .S WAITSPACE CR ; Notice here that we could simplify the code by creating a definition: : Debug CR ." Arrived at Position " . .", and stack = " .S WAITSPACE CR ; Then we could use it like this: 1 Debug 2 Debug 3 Debug etc. etc. Can you see how this works? Of course, in this example, the program itself is outputting text to the screen, and the debug stack information will be mixed in with the program text output. This is messy, but it does not really matter about the mixed screen output provided that you get the information you require. Notice that we included "CR" commands at the start and end of each debug line so that the debug text could more easily be separated from the program output. Of course, in a real debugging situation you would probably not have debug lines for EVERY sub-command, and you could organise your text output by sending debug text to a different stream if you wished. This sort of thing is down to personal style, and the important thing is that you know how to use this technique as a tool for debugging when required. Often you only need to do this sort of thing for quick "rough and ready" checking, and it is usually not worth bothering about setting up special text streams etc.. Let us now go back and look again at our original command line, where we typed in the parameters before we ran the program: 12 12 PrintAddress WAITSPACE Notice here that the useful command "WAITSPACE" is being used once again. The "WAITSPACE" will allow us to observe the results of the program without anything else printing to the screen until is pressed: in this case we shall be able to observe our address printout without the HeliOS "end of session" text disturbing the display until we press . This is often quite useful, and you will probably find it convenient on many occasions to use the WAITSPACE command to halt a program temporarily. ------------------------------------ Order of creation of HeliOS commands ------------------------------------ Notice that when we collected together all our sub-commands into the small program we constructed our main command "PrintAddress" last, AFTER we had made all our sub-commands. If you think about it, this is obviously necessary, because you cannot instruct HeliOS to use any command which you have not yet taught it! In general, when writing HeliOS programs, you must always progress from simple words using HeliOS CORE functions to more complex compound words which can use commands you have already created earlier. There are various ways to avoid this strict necessity for sequential command creation (usually via what is called "vectored execution"), but don't worry about this until a later more advanced tutorial..... So this is another important general rule: * NEW HELIOS COMMANDS CAN ONLY CALL DIRECTLY EITHER: 1. HELIOS CORE COMMANDS OR 2. COMMAND WORDS YOU HAVE DEFINED EARLIER IN THE PROGRAM *********************************************************************** -------------------------- Organisation and structure -------------------------- In the example above we made a small attempt to improve the organisation of our program between the stages of planning and final implementation. Although the processing of information in a computer is essentially sequential in nature, and your early programs will be simple sequences of commands, it should soon become apparent that some degree of planning and organisation is necessary to design an efficient program. The fact is that computer programs contain structure, with small parts of the whole working together in sometimes complex ways. Once you begin to write programs which can behave differently with different inputs, for example, you can start to generate quite a high level of complexity. There is never "only one way" to perform any complex task, and you will often be faced with many ways of implementing a certain programming requirement. Always look carefully at the overall "structure" of your programs, and at the way you have broken complex operations into smaller tasks. This is very important, and good organization goes together with sensible and logical structuring of commands. Of course this is a very personal thing, and what is sensible to one person is idiotic to another! In spite of this, there IS often an overall optimum strategy which may be determined by the constraints of the way the computer works. In general you should try to balance economy of code with speed and simplicity of operation: there will always be constraints and tradeoffs, but you should always be in sufficient control to strike a good balance. You should always PLAN your programs in such a way that there is minimal duplication of effort, and you should always try to keep a view of the greater whole as well as the individual parts. In HeliOS programs you will: 1. Break down large tasks into smaller sections. 2. Choose appropriate and sensible names for these sub-commands in order to make your programs comprehensible and easily readable. 3. Break down your sub-commands into still smaller and more manageable sections until you reach the lowest level of simple CORE commands. Simple sequential programs are fairly straighforward in terms of logical design, but you will encounter circumstances where your program has to behave differently according to external or internal conditions. The way sequential computer operations can be made to "adapt" with respect to time and different circumstances is responsible for much of the fascination of computer programming. Computers would not be capable of nearly so many useful functions if they could only carry out sequences of preprogrammed tasks. In fact computers are ingenious in that they can take "decisions" and modify their behaviour depending upon the results of their own actions. This "intelligent" behaviour comes, amazingly, from a simple use of logical operations such as: * Waiting for a certain condition to be "true". * Doing one of several different things depending on a condition. * Repeating "similar" or "modified" actions depending upon conditions. * Counting and performing multiple tasks. * etc. etc. These considerations of "contingency" allow even the simplest of computer programs to have non-linear structures, and it is here that flexiblity and intelligence on the part of the programmer come to the fore. So, we have two forms of "structure" to consider in our early programming efforts: 1. Structure in terms of the breakdown of tasks into manageable "chunks", which really means structure in terms of code modularity and function. 2. Structure in terms of logical behaviour, response to external or internal conditions, time related constraints etc. ----------------------------------------------------------- Using IF...ELSE...THEN constructs in conditional statements ----------------------------------------------------------- Here is a simple HeliOS conditional construct, showing how a program can easily interact with the outside world: : PressSpace? ." Please press a key." \ Ask for user input CR \ CR = Carriage Return KEY \ Wait for a keypress 32 \ 32 = Code for = \ Key = ? IF ." Space was pressed!" \ Yes! ELSE ." Space was not pressed!" \ No! THEN CR \ CR = Carriage Return ." Thank you!" \ Finished! ; Here you can see that one of two different logical paths will be taken by the program depending on user input. Look how HeliOS implemented the "conditional" construct of IF...ELSE... THEN. Here is what happens in the above program: 1. We print a message and then do a "carriage return". This is easy. 2. We use the HeliOS CORE command "KEY", which waits for user input and returns a numerical value depending upon which key was pressed. The stack diagram of KEY would be ( - - - KeyValue ) This means that after KEY there is one number, an input code, on the stack. 3. The next entry in our program is "32", which puts the number 32 (the key code for ) onto the parameter storage stack, on top of the input code. We now have two numbers on the HeliOS stack: ( KeyValue, 32 - - - ). 4. The command "=" is used to compare two numbers which are fetched from the stack. As "=" gets the numbers from the stack it removes them, leaving the stack empty. When "=" has compared the two numbers, it will place a result flag onto the stack. A "1" will be left on the stack if the two numbers were equal, and a "0" will be returned if they were unequal. The stack diagram of "=" is ( number1 number2 - - - Flag ) 0 or 1 or, in our example: ( KeyValue, 32 - - - Flag) 5. Now comes the important part: the use of the conditional "IF" command. The command "IF" removes a number (the flag) from the stack and does one of two different things according to whether the flag is zero or non-zero. If the flag value is non-zero, the code immediately after "IF" will be executed up to the point where either "ELSE" or "THEN" occur. If the number is zero, the code immediately after "IF" will be skipped and execution of code will continue immediately after the first occurence of "ELSE" or "THEN". 6. The "ELSE" and "THEN" determine the code which will be executed after "IF", depending on conditions following the "=" comparison. 7. The program completes by ALWAYS executing all the code after "THEN", in this case with a simple exit message. Here is another way to use IF and THEN. : PressSpace? ." Please press a key." \ Ask for user input CR \ CR = Carriage Return KEY \ Wait for a keypress 32 \ 32 = Code for = \ Key = ? IF ." Space was pressed!" \ Yes! THEN CR \ CR = Carriage Return ." Thank you!" \ Finished! ; This was actually simpler! We simply used "IF" to determine whether or not to print our message, and we have no alternative action defined by the "ELSE" command. Look at these simple conditional constructs and make sure that you really understand what is happening. In particular, try to follow exactly what is happening to numbers on the stack. Here is the first program again with stack comments: : PressSpace? ." Please press a key." \ Ask for user input Stack = Empty CR \ CR = Carriage Return Stack = Empty KEY \ Wait for a keypress Stack = Input 32 \ 32 = Code for Stack = Input, 32 = \ Key = ? Stack = Result IF \ Stack = Empty ." Space was pressed!" \ Yes! etc. ELSE ." Space was not pressed!" \ No! THEN CR \ CR = Carriage Return ." Thank you!" \ Finished! ; Important Notes: * Always remember that IF...ELSE...THEN constructs must always be contained within colon definitions: you cannot use these kinds of logical constructs in code which is being directly interpreted. * IF...ELSE...THEN constructs must be wholly contained within discrete word definitions: you cannot implement an IF...THEN...ELSE construct between different colon definitions. * IF...ELSE...THEN constructs can be freely "nested" within each other, to any level you wish. Now you know how to build very complex conditional statements if required, but beware of making these constructions too complex. If your code starts to become top-heavy with nested conditional statements, you can generally be sure that there is a better (more efficient and easier to read and debug) way of doing things. Often it is easier and faster to use such things as vectored execution (see later) rather than having a whole series of hard to follow in-line conditional statements. --------------- Combining flags --------------- There is another useful set of techniques which might help you simplify your conditional constructions, and these involve the various ways of combining "truth" flags. If you have several different flags to test it can often be convenient to use the "OR" function to combine them. Since "IF" is only interested in whether a flag is zero or non-zero, it is easy to combine any number of separate flags into one value by simply using a bitwise OR. You can also combine flags using logical AND and XOR operations, and in many cases these techniques are very useful, but be careful in doing this that you are operating on flags with compatible bit structures. This means that while it is OK to do an AND test on two flags whose values MUST be either "1" or "0", you would cause an error if you tried to combine two flags which could take different non-zero values. For example: 1 1 AND = 1 -> OK 0 1 AND = 0 -> OK 1 0 AND = 1 -> OK 1 2 AND = 0 -> NOT OK (Both flags are non-zero, or "true", but the combination of both with AND is false) Always remember in these cases that you are dealing with bitwise operations. ---------------------------------- Functions, Data and Error Checking ---------------------------------- Another way of analysing a program is in terms of the way "functions" are used to operate on "data": whether a command "DOES" something (like the addition function) or simply "IS" something (like a number which is added). The syntax of some languages strictly controls how these different categories are represented, to help you ensure that you write your code in a way which prevents "incorrect" expressions and mixed parameter use. HeliOS has no such enforced constraint, although you can, if you wish, invent naming conventions for yourself by using certain prefixes for certain types of function etc.. Yet another abstraction is to specify the TYPE of "data/something" which you are dealing with. In some languages there is a very strict limitation concerning which types of data each kind of function may operate upon. This kind of "artificial" abstraction can have its uses, especially in helping the computer language to "enforce" so-called "correct" programming techniques. However, checking all these things takes valuable computer time and also enforces a rigid "straightjacket" on the programmer. The fact is that all these "human" intellectual abstractions are basically an imposition upon the way the computer works, since to a computer ALL data is simply numerical and all processes obey a very simple binary logic. Not only this, but restrictive rules built into a computer language can also soon become very irksome to an experienced programmer who is accustomed to greater freedom. HeliOS keeps things simple and efficient, staying close to the way the computer CPU works and avoiding too many artificial constraints. HeliOS, therefore, has no enforcement of such things as "data types", and does very little by way of enforcement or error checking (Although since HeliOS is extensible and user-definable you could build such a system for yourself if you wished to do so). HeliOS provides a comprehensive and powerful set of logical tools such as looping, timing, and conditional constructs. It provides all the usual data constructs such as constants, variables, text strings, data structures and pointers. It then leaves you free to evolve your own methods....... HeliOS does, however, enforce "structured programming" in that it will not easily allow you to jump from place to place forward and backward in your code. This is a good thing, because if allowed to do so most beginners tend to write a tangled web of "spaghetti-logic" code and then often give up before they have managed to disentangle themselves! In general HeliOS programs progress logically and sequentially using simple logical constructs such as IF....ELSE....THEN or BEGIN....UNTIL. HeliOS keeps things simple, free of constraint, and powerful. It us down to you, the programmer, to make sure that you use this freedom wisely, because HeliOS will not waste time checking for your mistakes or forcing you to do things "right". ------------------------------------------------------------------ The HeliOS vocabulary, the dictionary, and the compilation process ------------------------------------------------------------------ Every command word which you create immediately becomes a fully fledged part of the HeliOS command set, and can be used exactly like a HeliOS CORE function. The name of the command is immediately entered in the HeliOS vocabulary, as can be verified by performing a vocabulary listing. When you create a new command, that command is instantly "compiled", which involves two things: 1. HeliOS creates a special section of code which will be executed when your new command is called. 2. HeliOS creates a new vocabulary entry. These two actions, when repeated, build up two sections of information in the computer's memory, and these two sections of information can be saved and reloaded. HeliOS saves all functional code in one memory block and all vocabulary "name" information in another separate memory block. As you will see later, you can actually dispense with the "vocabulary" data when "running" a stand-alone HeliOS program. The vocabulary data is really a simple reference listing of command words which is only required when you are initially compiling a program or using the HeliOS interpreter. Here are two important statements which you should try to understand and bear in mind as you work with HeliOS: 1. INTERPRETING: When HeliOS "interprets" a command word the function associated with that word is actually performed, and nothing is aded to the vocabulary. 2. COMPILING: When you ask HeliOS to "compile" a new command word using a colon definition this is what happens: a. The new command name is added to the vocabulary b. The command functions whose names comprise the "body" or "program" of the new word will NOT (usually) be performed directly, but will be stored as the code part of the new word. c. The newly compiled code which defines the new command function will not be executed until later, when the new command name is eventually used in INTERPRET mode. Here are two examples: 1. ." Hello World!" - Prints "Hello World!" and does not compile anything. This is an example of INTERPRET mode. 2. : HELLO_WORLD ." Hello World!" ; - Prints nothing but compiles a command called "HELLO_WORLD" which WHEN EXECUTED OR INTERPRETED LATER will print "Hello World!". This is an example of COMPILE mode. Note that you can always examine the current HeliOS vocabulary by using the Interpreter menu functions or the command line functions: VLIST - Display CORE and USER vocabulary. UVLIST - Display USER vocabulary. CVLIST - Display CORE vocabulary. So far we have referred generally to the set of HeliOS available command words as the VOCABULARY, and to the documentation describing and defining these commands as the DICTIONARY. This is correct, but in FORTH the term DICTIONARY is also traditionally used to refer to the actual memory area where all commands are stored. In traditional FORTH the dictionary memory was used to store both command names and code, but HeliOS uses a rather different internal arrangement with the command names stored separately. HeliOS documentation and usage adheres to FORTH conventions by continuing to use the term DICTIONARY loosely to refer to the memory area where the code for compiled words is stored. You will see a readout of the current available dictionary space at the top left of the HeliOS status display. Once a command word is in the vocabulary, HeliOS will always understand this word if you type it in your programs or at the command line. In fact, just like a person, HeliOS "understands" your instructions by interpreting words, like this: 1. HeliOS scans everything you write, one space-delimited word at a time. 2. It looks up each word in its vocabulary. 3. If it finds the word in its vocabulary it carries out the associated command function. 4. If it does not find the word in its vocabulary, HeliOS will try to find a matching symbol in its include files, and if it does so the numeric value for that include symbol will be substituted for the symbolic name. 5. If HeliOS cannot find the word in either its vocabulary or include symbol lists, it tries to interpret the word as a pure number. 6. If all these options fail HeliOS issues a warning to you and stops the process of interpreting immediately. To summarize, here are simple definitions of the "technical" terms used when referring to program compilation/interpretation: EXECUTION = HeliOS takes a given word and carries out the associated code. INTERPRETATION = HeliOS reads your input and acts upon it by executing command words sequentially. COMPILATION = HeliOS creates a new command and stores the name and the associated functional code. In case you are interested in more details, here is a brief description of how HeliOS carries out compilation of a colon definition: * HeliOS reads the input text and finds the colon character. * It then EXECUTES the code associated with the COLON command word. * The COLON command code, when EXECUTED, does several things: (To start with HeliOS is in "interpret mode".) 1. It COMPILES the following word, the command name, into the vocabulary. 2. It sets up an internal operational MODE such that HeliOS will now COMPILE all following words into the dictionary, until a SEMICOLON is encountered. (HeliOS is now in "compile mode".) 3. It continues to COMPILE each successive word into the body of the new word. 4. It finds a SEMICOLON and terminates the new word definition, reverting back to INTERPRET mode. (HeliOS is now back in "interpret mode".) ----------------------------------------- The concepts of RUN-TIME and COMPILE-TIME ----------------------------------------- It will be more apparent to you what these terms mean when you have used HeliOS for some time, and we will cover these matters is more detail later, but even at this early stage we should give a brief mention to these two important concepts. For any command word: COMPILE-TIME is the time when the word is compiled RUN-TIME is the time when the word is executed, either when a program executes or when a word is interpeted at the command line. This sounds simple and obvious but there are subtleties to the situation! For example, when a new word is being created, it is "RUN-TIME" for the HeliOS command words which actually DO THE COMPILING, but "COMPILE-TIME" for the new word itself. In other words, the terms RUN_TIME and COMPILE-TIME relate to states of particular words at a given time, and NOT the HeliOS system as a whole. ----------------------------------- Creating standalone HeliOS programs ----------------------------------- By the term "standalone" we refer to the situation where you want to use or distribute a HeliOS program without the main HeliOS Interpreter. This topic is discussed in other parts of the HeliOS documentation, but here we will give you a simple tutorial introduction. Before discussing the generation of standalone programs we should perhaps mention again here that HeliOS has an "autorun" feature in which the last word in a program will automatically be run when the code is re-executed in a standalone environment. Thus you should always set up the last colon definition of a standalone program as the startup code for the program. HeliOS has two methods of generating standalone programs, and each has advantages and disadvantages: 1. Generating a (small in size) overlay program file for use with the separate HeliOS_exe executive program. This method has the advantage that you can put several HeliOS programs on one disk with just the one large executive file which can be used by all of the individual programs. This method has the disadvantage that you need two files to run each of your programs, using an AmigaDOS command such as: HeliOS_exe MyProgram Note that the HeliOS executive is typically 250k in size, but when packed this reduces to around 100k. 2. Generating a single standalone executable HeliOS program. This method has the advantage that you have just one file. This method has the disadvantage that each HeliOS standalone executable has to contain all the HeliOS support code. This gives a large file size for each HeliOS program, and even the most tiny program has the same executable overhead. The HeliOS executable is typically 250k in size, but when packed this reduces to around 100k. We will now look at methods of generating the various kinds of HeliOS program code, concentrating on the use of the PRESAVE function which is found in the Interpreter menus. If you examine the Interpreter menus you will see that there are menu options to configure the PRESAVE output compilation process into three distinct modes: 1 -> Compile dictionary 2 -> Compile overlay 3 -> Compile standalone These options cause the PRESAVE function to save different kinds of program files as follows: Compile dictionary - This causes TWO files to be generated and saved by the PRESAVE function. These files are a main program overlay file and a vocabulary overlay file for use when the program is to be PRELOADED back into the main Interpreter. In this process the vital information which makes up a HeliOS program is split into two parts, one containing the program code itself, and the other containing "vocabulary" information required for the Interpreter to be able to associate keyboard input with functions defined within the program. The main program file is given a ".cmp" suffix, and the vocabulary file a ".cmpv" suffix. Both these files should be kept together, and both will be automatically loaded when you use the PRELOAD function. Note that when using the PRELOAD function you only need to select the ".cmp" file, because the ".cmpv" file will be automatically loaded at the same time by the HeliOS system. Compile overlay - This causes a single file to be generated for use with the "HeliOS_exe" standalone executive program: this file simply contains the program code in a concisely packed form. The standalone executive does not make any use of vocabulary information, so it only requires the program code overlay. Compile standalone - This causes a single executable file to be generated, which can be run directly on its own. Note here that a standalone single executable HeliOS program can ONLY be generated from the main Interpreter, but the overlay files can also be created by using the standalone compiler "HeliOS_cmp". We will now give a few direct practical instructions on how to generate standalone HeliOS programs. * To save a HeliOS standalone overlay 1. Load and compile your program, remembering that the last word in the program will automatically be run when your code is re-executed in a standalone environment. 2. Select the "Compile overlay" Interpreter menu option. 3. Select the "Presave" Interpreter menu option to save the overlay. 4. Execute your program using the AmigaDOS command line: HeliOS_exe MyProgramOverlay * To save a fully independent HeliOS executable 1. Load and compile your program, remembering that the last word in the program will automatically be run when your code is re-executed in a standalone environment. 2. Select the "Compile standalone" Interpreter menu option. 3. Select the "Presave" Interpreter menu option to save the executable. 4. Execute your program using the simple AmigaDOS command line: MyProgram N.B. Remember to re-select the "Compile dictionary" Interpreter menu option when you wish to return to saving and loading full Interpreter-based HeliOS programs. * An important point to remember.... There is one final point of interest here which you will find very useful when compiling compact HeliOS program disks. The "HeliOS_exe" file is an ordinary AmigaDOS executable file which is provided on your HeliOS master disks in uncompressed form. If you wish, you may use a packer such as PowerPacker to compress this executable into a file somewhat less than half the size of the original, thus enabling you to save space on any of your HeliOS program disks which run HeliOS overlay files using HeliOS_exe. Please note however that the copy of "HeliOS_exe" which resides in your master "HeliOS:" directory MUST NOT BE PACKED. This is because this file is used in its UNPACKED form by the main HeliOS Interpreter program when it is creating standalone executables. If you pack the "HeliOS_exe" file which is in the HeliOS: directory you will find that all standalone HeliOS programs created from the Interpreter will not work at all. ---------------- The HeliOS Stack ---------------- As mentioned above, the stack is a place where HeliOS stores numbers on a temporary basis. It is rather as if HeliOS were to say to the stack "Here you are, please hold these for me while I go and do something else! Please give them to the next person who asks for them.". The stack, as its name implies, is rather like a pile of data items, and each new item simply goes onto the top of the pile/stack. Look at this simple diagram: a <---- 1st item or "Top of stack item" b <---- 2nd item c <---- 3rd item d <---- 4th item etc. etc. Let us put just one number, the number 4, on the stack: 4 <--- Top of stack Now let us put just another number, the number 8, on the stack: 8 <--- Top of stack 4 <--- 2nd place on stack Notice how each new number becomes the "top" number and displaces any other numbers downwards. If a computer, which is a simple minded creature, wants to do something like an addition sum, it cannot do this quite so flexibly as we can. Faced with the problem of adding 4 to 8 to give 12, we clever humans might think something like this. "Ah, first I see the number 4: lets see what we need to do with it." "Oh, I see a "+" sign, so I need to find another number to add." "There it is: 8. I will add them together. The result is 12." "Whether I write 12 down or just remember it, I KNOW the answer was 12". Or we might look at it differently, like this: "Ah, two numbers 4 and 8." "What is it that I have to do with them?" "Ah, I see, a "+" sign, so I will add them together to get 12" "Whether I write 12 down or just remember it, I KNOW the answer was 12". Or we might look at it differently again: "Ah, a "+" sign." "This needs two numbers to add, so what are they?" " I see, 4 and 8, that gives 12." "Whether I write 12 down or just remember it, I KNOW the answer was 12". You might think all these are boringly similar and obvious, but a computer does not even have this limited choice. Putting it simply: * A computer has NO choices about how to carry out an operation. * A computer needs to have its DATA loaded FIRST into its processing unit's data storage space. * A computer carries out an operation like "+" by ASSUMING that data has ALREADY been stored in its processing unit data storage space. * A computer has no automatic "COGNITIVE MEMORY" or "KNOWLEDGE". * A computer simply places the result of its calculation in its processing unit's data storage space, then carries on and forgets what has happened. So, to perform and store an addition, a computer program needs to: 1. Get the first number 2. Get the second number 3. Add them together 4. Store the result The computer is quite inflexible and can work in no other way. If you write an addition "sum" like this: 4 + 8 and pass it to the computer (as some computer languages do) the computer has to be made to carry out various extra manipulations INTERNALLY by the computer language BEFORE it can do the calculation in the form it can work with. This is slowing everything down because more work is having to be done UNNECESSARILY by the computer. This is something like what the computer language would have to do internally, unseen by you: 1. Read the first number. 2. It does not know what to do with it yet, so it stores it. 3. Read the "+" command. 4. It looks up the "+" command to see what this command does when it executes. 5. It sees that two numbers are required for this command. 6. It stores or "remembers" that it is about to do a "+" operation. 7. It gets the second number and stores it. 8. It goes back to recall what command it was performing. 9. It performs the addition. On the other hand, if YOU supply the computer with its data in the form in which it can handle it directly, you get much faster operation. If you write the "sum" above like this: 4 8 + look how easy it is for the computer. 1. Get a number onto the stack 2. Get a number onto the stack 3. Execute the "+" command, which takes two numbers off the stack and replaces the result on the stack. The operation is over quickly and efficiently, the computer can go on to do something else, and the result is automatically "remembered" on the stack, where YOU can do something with it. This means that computers can work more efficently, in general, by being given numbers first, followed by function commands. This is how HeliOS always works, because we are only interested in maximum speed and efficiency: wherever the programmer can save the computer extra work the program will run quicker. The stack is a nice quick and simple "universal" storage area which is organised internally in such a way the HeliOS can feed the computer's central processing unit directly from the stack very quickly indeed. The method of putting numbers on the stack BEFORE the operator function is performed is called POSTFIX notation or REVERSE_POLISH notation. The more usual "human" method of putting the operator IN-BETWEEN the number parameters is called INFIX notation. HeliOS uses postfix notation rather than infix notation for another good reason besides the one mentioned above. Much of the power of HeliOS is derived from the fact that postfix notation allows a very elegant and simple mechanism for passing parameters between command functions. Look at these examples: The function "+" gets two numbers from the stack and adds them. The function "FPENSET" gets one number from the stack and sets a pen colour. The function "CURPUT" gets two numbers from the stack and sets the cursor. So we can have a word like this: : FANCYPRINT 12 + CURPUT FPENSET ." Hello!" ; with a stack diagram ( Colour, Column, RowOffset - - - ) Look what happens here: The function FANCYPRINT will expect three numbers already on the stack: RowOffset <- Top of stack Column <- 2nd on stack Colour <- 3rd on stack It then puts the number 12 on TOP of the others: 12 <- Top of stack RowOffset <- 2nd on stack Column <- 3rd on stack Colour <- 4th on stack It then adds 12 to the RowOffset value, giving a cursor displacement offset from "Row 12", which is where we want to place our text. This "final" calculated Row value is placed back on the stack: RowOffset+12 (= Calculated Row position) <- Top of stack Column <- 2nd on stack Colour <- 3rd on stack The function CURPUT is then executed, and we know that CURPUT takes two numbers from the stack and places the cursor at that position. The stack now looks like this: Colour <- TOP of stack The function FPENSET is then executed, and we know that FPENSET takes one number from the stack and sets the text colour. Finally the ." function prints the following text. Look at this carefully to see how simply the parameter passing works, and then try to work out how it might work with INFIX notation. You will probably agree that although it may be initially rather "strange" compared to our habitual "human" use of INFIX notation, POSTFIX notation is a great way of controlling a computer program! Since HeliOS is concerned with helping you control your Amiga in the most efficient way possible, you are going to HAVE to do your share of the work and learn to use the stack and POSTFIX notation. You will find this really very easy after the first few HeliOS programming sessions, and you will notice that the HeliOS Interpreter has a "real-time" permanent stack display to help you get used to how the stack operates. Try doing some simple arithmetic operations in the Interpreter and watch the way the stack display changes. Stick with this until you really are confident that you have grasped the way the stack works, because this understanding is absolutely vital to everything you will do in HeliOS. You may find it useful to try these simple command words: + Adds (and removes) the top two numbers on the stack, then puts the result back on the stack - Subtracts (and removes) the top two numbers on the stack, then puts the result back on the stack . Prints the number on top of the stack and removes it .s Prints all the stack contents without changing anything DUP Duplicates the top stack number SWAP Exchanges the top two stack numbers ROT Moves the 3rd number on the stack to the top OVER Duplicates the 2nd number on the stack on top of the stack These last four words are called "stack manipulation" words. There are many of these stack manipulation words in the main HeliOS CORE vocabulary. Look at the "Dictionary.doc" now and read the notes concerning these words, then try using a variety of them to become accustomed to the way the stack can be manipulated. Having done this you will have had some experience of what is called "stack management". Stack management is very important in HeliOS, and you can imagine that in any language which uses stack parameter passing you will very often have the need to adjust and modify the stack. This can actually be quite interesting and often even becomes addictive, in the manner of a puzzle, with many programmers taking delight in managing very complex stacks. Which brings us to another VERY important rule: * Do NOT attempt to work with large stack sizes! The stack is designed for quick and simple parameter passing, and if you find that things are getting complicated you should either break down your program into simpler more manageable chunks or resort to other techniques such as using named constants and variables. We will explain constants and variables later, but basically these allow you to manipulate numbers using names rather than simply referring to a position on the stack. You will find that in some cases the stack is more efficient, and sometimes using constants and variables is better. You will soon learn your own programming style and preferences, but you should NOT try to avoid using the stack by using methods you might be accustomed to from other programming languages: the stack is a dynamic and efficient programming tool, and MUST be used properly. Finally here are two more terms which you will find used in reference to the stack: "Stack overflow" This means that there are too many numbers on the stack. "Stack underflow" This means that there are too few numbers on the stack for a given function. ************************************************************************** End **************************************************************************