home *** CD-ROM | disk | FTP | other *** search
Text File | 1994-10-31 | 186.1 KB | 6,053 lines |
-
-
- Chapter 2
-
-
- Tutorials
-
-
-
-
-
- BASIC is just one of many computer languages
- that you can buy for your Amiga computer (you
- could contact HiSoft for up to date details of
- the range available) but BASIC is deservedly
- popular for its ease of use and the speed with
- which a beginner can learn to produce results.
- On the other hand there are two common
- criticisms of BASIC. Firstly, many people feel
- that its very flexibility and tolerance
- encourages poor programming habits compared to
- highly structured languages such as Pascal.
- Secondly, BASIC is often the slowest language
- you can use, which makes it unsuitable for many
- time-dependent applications such as games and
- graphics.
- Our new BASIC, MaxonBASIC 3, goes a long way
- towards solving both of these problems. We have
- taken the best qualities from Microsoft BASIC,
- Pascal and other languages and combined them
- together to produce an implementation that is
- capable of running traditional BASIC programs
- but can also be used to produce a source that
- is highly structured, easy to follow, and
- simpler to debug. It is also extremely
- powerful, giving you the ability to control
- almost every feature of your computer, hardware
- and softwareÉ and, above all, it is fast.
- Many people familiar with older versions of the
- language will have some re-learning to do. Bad
- habits and unnecessary features, such as line
- numbers, can now be forgotten, although you can
- use line numbers if you really want to.
- MaxonBASIC does not mind if you want to take
- things gently and continue using them for a
- while.
- To help you get to grips with BASIC and, in
- particular, MaxonBASIC, we have written a
- tutorial which forms the rest of this chapter;
- this is aimed at users who have not used BASIC
- very much before and starts from first
- principles; experienced users may find it
- useful as a refresher course.
-
- Throughout the tutorials you will see some
- text marked with sidebars, as this
- paragraph is marked. These passages are
- diversions which need not be read the
- first time through but contain
- supplementary information which you should
- find useful once you have become more
- confident with MaxonBASIC.
-
-
- BASIC Tutorial
-
- The examples used in the following tutorial are
- designed to illustrate the power of MaxonBASIC.
- They will therefore tend to use its structured
- elements as much as possible, but do remember
- that you can also type in many programs from
- books and magazines that would work with more
- inferior versions of BASIC. They should run,
- and run much faster, with hardly any alteration
- at all; if there are problems, MaxonBASIC will
- point you towards which lines are causing the
- trouble, quickly and simply.
- All computer programs are simply tools which
- allow us to control the actions and reactions
- of the computer itself. MaxonBASIC has been
- written to be as compatible as possible with
- several different versions of the language -
- notably AmigaBASIC that came supplied with
- older Amiga´s and also Microsoft QuickBASIC
- which is one of the most highly respected
- implementations of the language available for
- the IBM PC range of computers (and compatible
- machines). Language elements have also been
- added from Borland´s Turbo Basic for the PC.
- We aimed at this compatibility for two reasons.
- Firstly, anyone who has already learnt to
- program in one of these different versions of
- BASIC will be quickly able to work with the
- MaxonBASIC language. Secondly, programs that
- are have already been written using these
- versions will run with little or no alteration
- under MaxonBASIC (but of course they should run
- much faster!).
- The latter feature is particularly important to
- anyone who intends to run a specific program,
- one that was originally intended for the IBM PC
- for example. It will also allow anyone who
- wishes to learn more about programming to buy
- tutorial books that were aimed to be used with
- one of these versions of the language.
- However, for anyone who is new to programming
- it is not all good news. MaxonBASIC has had to
- conform to the language standards used by at
- least two different systems, and these in turn
- have built upon previous versions of BASIC and
- so on. As a result not all commands are as self
- explanatory or as easy to use as we, or you,
- might wish. One area of difficulty is that,
- because MaxonBASIC is compatible with so many
- other BASICs, it has a large number of Reserved
- Words that you should avoid using as labels or
- variables e.g.
-
- Loop:
- PRINT "Welcome to MaxonBASIC!"
- GOTO Loop
- If you typed this program in and tried to
- execute it using MaxonBASIC, you would find
- that an error will occur on line 3. This is
- because Loop is a reserved word in MaxonBASIC
- (you will learn how to use it later) and thus
- you cannot use it as a label or variable. You
- must watch out for this type of error since you
- can easily confuse MaxonBASIC by using its
- reserved words incorrectly. See Appendix C for
- a list of the Reserved Words.
-
- Experienced programmers, who are sure that
- they know what they are doing, can remove
- a Reserved Word so that it can be re-
- defined. You do this with a line like:
-
- REM $DISABLE PRINT
-
- to remove PRINT from the Reserved Word
- list. You can then create a new sub-
- program or function called PRINT.
- This tutorial is intended to be a complement to
- the Command Reference section of this manual.
- Unlike the latter, here keywords are grouped
- logically by their general function rather than
- alphabetically. We have tried not to duplicate
- information that is perfectly obvious from the
- Command Reference, but rather to summarise the
- way that certain keywords are related to each
- other and interact with each other. At times it
- has been inevitable to make forward references
- to keywords or programming techniques that have
- not yet been covered in detail, but we have
- tried to keep these instances to a minimum.
- Please consult the Command Reference chapter
- frequently as you work through this tutorial -
- you will find understanding will dawn more
- quickly and more easily if you supplement your
- knowledge in this way.
- After the first few programs presented in this
- tutorial it will be assumed that you know how
- to use the MaxonBASIC editor; the various
- demonstration programs will be presented
- without constant reminders of how to enter and
- run them although we will give examples of
- editing techniques etc. from time to time. If
- you need further help, you should consult
- Chapter 3 on using the editor.
-
-
- The Building Blocks of BASIC
-
- We can look on each component of the BASIC
- language as a building block from which we can,
- step by step, construct an entire program. As
- we shall see later, the structured aspects of
- MaxonBASIC make it particularly easy to develop
- very long and complex tasks as a collection of
- small modules, each one of which performs a
- small part of the whole and which can be tested
- and perfected in isolation.
- The smallest component of the BASIC programming
- language is known as a keyword. Each of the
- keywords does a certain job, although some of
- them must first be given some information to
- work on, and many of them only function when
- used in conjunction with certain others.
-
- For your reference, a list of all keywords used
- by MaxonBASIC is given in Appendix C. You must
- ensure that you do not try to use any of these
- words to represent variable or subroutine names
- or MaxonBASIC will become confused as to which
- you really mean.
- The function and syntax of every single keyword
- will be detailed in the Command Reference. This
- tutorial section will not attempt to cover
- every one of these again, but rather try to
- illustrate the way that some of these building
- blocks can be joined together into useful
- routines.
- The most important thing is that you learn to
- ´think like a programmer´. Once you begin to
- see how small programs work, how the individual
- commands fit together to produce the desired
- end result, you will quickly be able to pick up
- new keywords as and when you need them.
-
-
- Some Simple Commands
-
-
- There are many very simple tasks you can ask
- your computer to do which really form the
- 4bread and butter´ of computer programs. The
- simplest example to start with is
- unquestionably a command like the BEEP command
- which, no prizes here, causes the computer to
- attract the user´s attention. We´ll try it now
- and enter a short program.
- Start by locating the HBasic2 file on your
- working disk or hard disk (see Chapter 1), then
- double-click with the mouse on the HBasic2 icon
- to run MaxonBASIC.
- After a short while, the editor window will
- appear.
- Now type the following, pressing the Return key
- at the end of each line:
-
-
- PRINT "Please wait for the beep ..."
- BEEP
-
-
- Now hold down the right mouse button and move
- the mouse up to the Program menu and, holding
- the button down, move the mouse until you have
- selected the Run command. Now release the
- button.
- This will run your program which should open a
- window, display its message and beep (flash the
- screen) É impressed?
- Ok, but it was simple to do.
- Press a key and select New from the Project
- menu to create a new window; we´ll move
- straight on to a more complex (and Amiga
- specific) command: LINE draws a line on the
- screen. By looking in the Command Reference
- chapter you will see that this keyword can be
- given several parameters which control the
- start location and finish location of the line.
- We will be dealing with LINE and other graphics
- commands again later in the tutorial, so do not
- try and take it all in at this stage. Just try
- this simple command for comparison with BEEP.
- Remember that it does not matter whether you
- type the MaxonBASIC commands in upper or lower
- case or even a mixture of the two; LINE, line
- and Line are all the same to MaxonBASIC.
-
- The editor will upper-case MaxonBASIC
- Reserved Words automatically if you have
- selected Show Keywords in the SettingsÉ
- requester from the Settings menu. This is
- useful as a quick syntax check after you
- have completed each line.
-
-
-
- PRINT "Just a short line ..."
- LINE (100, 100) - (200, 200)
-
- You can run this as before, by selecting Run
- from the Program menu or you can run it by
- using a keyboard shortcut, Ctrl-X - it achieves
- exactly the same as selecting Run but some
- people prefer the keyboard to the mouse. There
- are many keyboard shortcuts within the
- MaxonBASIC editor.
- Press a key so that you are back looking at the
- source code of the LINE program, then select
- New from the Project menu to create a new
- window. By this point we have several windows
- open, so click in the Close box, at the top
- left of the window, of our two earlier programs
- to forget them - click Lose when the requester
- appears.
- The commands that you can give the computer
- must be presented in a fairly rigidly defined
- style and format known as the command syntax.
- The correct syntax for every command you use is
- given in the Command Reference chapter. Program
- syntax can be compared to the grammar of the
- English (or any other) language; if you want to
- make yourself understood to other people you
- should speak and write reasonably correct
- English. In the same way, you must be careful
- to write your BASIC programs correctly for
- MaxonBASIC to understand what you mean.
- One thing computers are very poor at (and
- people are normally rather good at) is guessing
- what we mean when we present them with
- ambiguous or incomplete instructions (which is
- why a computer can do many engineering tasks
- but will probably never have a career in
- politics).
- For example we cannot use the commands:
-
-
- LINE 100 100 200 200
- LINE 100:100:200:200
- LINE (100)(100)(200)(200)
-
-
- and expect the computer to do what we wanted,
- we must obey its own rules and not invent our
- own. Try typing in the first line above and
- running it (Ctrl-X, remember?).
- You should find that an error requester appears
- and you are asked to Continue, OK or Stop?
- Select Stop and you will be returned to your
- source code window.
-
-
- Something has gone wrong, the program did not
- run. Look to the top right of the window, you
- should see an error message (Open bracket
- expected instead of 100) - was that what you
- expected? MaxonBASIC knows what it wants and
- has told you quite clearly - unfortunately,
- error messages are not always so obvious.
- Errors in syntax rather than logic are among
- the most common mistakes beginners to computing
- make. Where it can, MaxonBASIC will make every
- attempt to catch these errors and explain to
- you what it cannot understand (if you think
- about it, to explain one´s own
- misunderstandings is something of a paradox so
- please be tolerant if MaxonBASIC does not
- always highlight the exact problem).
- At this stage it is useful to cover a valuable
- keyword; the REM or ´do nothing´ command. REM
- is actually short for REMark and anything you
- type on a program line after this keyword will
- be ignored by MaxonBASIC, whether it contains
- valid keywords or just plain ordinary English.
- The main use of the REM command is to allow you
- to add notes to your program which explain what
- it is the next section of the program is
- intended to do.
- REM is also invaluable for catching obscure
- mistakes (or ´bugs´) in your program where you
- have got the syntax of the program correct but
- there is an error in the logic which the
- compiler may not be able to spot. If you have
- commented your program clearly it is often
- possible to quickly isolate and identify where
- the problem lies.
-
- REMs can also be used to ´switch off´
- sections of the program that you have
- tested and know work correctly, so that
- the parts still under development can be
- run in isolation.
- There is an abbreviation for REM - the ´
- (single quote/apostrophe) mark. This is
- particularly useful for commenting out program
- lines, because it is quicker to insert.
- Much more useful than our friends BEEP and
- LINE, but also more complex, is the PRINT
- command which is used to get the computer to
- put information on the screen, as we have
- already seen above. Extremely impressive
- tabular effects are possible using the most
- sophisticated options of this command but,
- since it is also an instruction that you will
- be using almost every time you program in
- BASIC, we might as well learn it quickly - it
- is after all one of the few means by which we
- can get the computer to tell us the results of
- any calculations or tests it has performed.
- In its simplest form the PRINT command needs no
- parameters beyond some indication of exactly
- what it is that you want displayed. One way to
- try it out is to use the computer as a, rather
- expensive, pocket calculator. Try entering some
- of the following short commands. Remember, use
- Ctrl-X to run the program and Close or AK to
- clear out the text.
- For deleting short programs, alternatives to
- closing the window are: position the text
- cursor at the end of the line and use the
- Backspace key repeatedly or position the cursor
- within the line and use the delete line
- command, which is Ctrl-Y.
-
-
- PRINT 23+45
- PRINT 12*6
- PRINT 99/9
-
-
- Of course it is possible to print text as well
- as numbers as so:
-
-
- PRINT "Ten times twenty six equals"
- PRINT 10*26
-
-
- To signal to BASIC that you want it to print
- the text as it is given, rather than attempting
- to look the words up as potential numeric
- variables (see below) the text must be enclosed
- in double quotes (""). Again this is an example
- of the need to use the correct syntax to avoid
- ambiguity.
-
-
- Layout of Programs
-
- Before we get too involved it is worth pointing
- out some simple points about the layout of
- BASIC programs.
- The highly advanced structured programming
- features provided by MaxonBASIC are intended
- primarily to allow the programmer to work in a
- clearly defined and modular way. These make it
- very much easier to follow the logic of what is
- trying to be achieved. However it is not only
- the language keywords that make this possible;
- the way that the listing is organised, on
- screen or on paper, is very important so that
- the programs are easy to follow.
- MaxonBASIC does not care whether the keywords
- you type are in upper or lower case, but they
- will be much easier for you to spot and to
- follow if upper case is used; in fact the
- editor helps you by upper-casing keywords
- automatically if you check Show Keywords in the
- SettingsÉ requester on the Settings menu. The
- editor also does not mind how many extra spaces
- are used to indent different lines of the
- listing - make full use of this feature and set
- out your modules so that the eye can easily
- follow the hierarchy of the program. Again the
- editor can help by automatically indenting
- lines; this is described in more detail later
- on.
- Like all modern versions of BASIC it is
- possible to put more than one command on each
- line, as long as each command is separated from
- the next by the colon character (:); this can
- be very useful to maintain the logic of the
- program.
- Unlike many versions of the language,
- MaxonBASIC does not need line numbers; you can
- use them if you wish or avoid them like the
- plague!
-
-
- Using Simple Variables
-
-
- The power of a BASIC calculator program such as
- we have written above can be greatly increased
- by the use of simple numeric variables. Again
- there is much more to the subject of variables
- than we will cover here, but in their simplest
- form they are just letters or short names that
- can be assigned a value, and used to represent
- that value in calculations (just as you would
- do in algebra, remember that?).
- Any text string or number that is used
- explicitly rather than assigned to a variable
- is a constant.
- As well as being useful and flexible tools for
- use in calculations, variables have the useful
- facility that they can be given descriptive
- names such as profit and sales which make it
- very much easier to follow the logic of the
- computer listing to see what each line is
- doing.
- So valuable is this feature that MaxonBASIC
- also allows constants to be given descriptive
- names as well. To denote that a given name is
- to be treated as a constant and not a variable
- we must use the keyword CONST.
- Try this example:
-
-
- CONST costs% = 1500
- sales = 2000
-
- REM Profit is simply sales less costs
- profit = sales-costs%
- PRINT "The expected profit will be"
- PRINT profit
-
-
- As a simple illustration of the usefulness of
- variables edit the first two lines of the
- program to give different values for costs% and
- sales; do this by placing the cursor at the end
- of the first line, pressing Backspace to delete
- the 1500 and entering another value. Repeat
- this for sales. Run the program and then close
- the window.
- Later in this tutorial we will see that the
- program can be extended to automatically ask
- you for values for these variables as the
- program is run.
- Variables can also be defined that hold text
- rather than a number. To warn BASIC that this
- is what you intend to do, syntax demands that
- all text variable names must end in the $
- character. In computer speak ´$´ is often
- pronounced ´string´ and represents ´a string of
- letters joined together´. The text that you
- wish to enter into the variable must again be
- enclosed in quotes.
-
- An example is:
-
-
-
- name$ = "High Quality Software"
- PRINT "HiSoft means ";
- PRINT name$
-
-
- Now run your program.
- You may have noticed something different about
- the way that the above program produced its
- output i.e. it is all contained on one line.
- This is the result of the semi-colon (´;´) at
- the end of the second line.
- The semi-colon is one of many possible ways we
- can control the way that PRINT statements are
- displayed, and these will be detailed later.
- For the time being though it is useful to know
- that the semi-colon ensures that any following
- print statement is added onto the end of the
- existing one, rather than starting a completely
- new line. We will be using this feature a lot
- when we start to look at programs that would
- otherwise very quickly fill the screen with
- information. Notice also the trailing space at
- the end of the second line - we need this to
- avoid running the words means and High
- together.
- The above programs are useful illustrations of
- how variables work, but they do not really
- reflect the way that we use them in real
- programs. The truth is that we often do not
- know in advance what the value of a variable is
- to be before the program is run. It is
- possible, as above, to edit the list of
- variables and recompile the program every time
- we use it, but a much more powerful and
- flexible method is of course to get the
- computer to ask you for the variable´s current
- value whilst the program is running. This is
- done using the INPUT keyword.
- If you use the keyword INPUT followed by a
- variable name, the computer will display a
- question mark on the screen and pause the
- program until it has had an answer from you, as
- in this example:
-
-
- INPUT x
- y = x * 10
- PRINT "Ten times"; x ; "equals"; y
-
-
- Of course, in a long and complex program we
- will want to be much more friendly than that -
- question marks appearing at random to request
- unspecified information can be rather
- confusing!
- The INPUT statement therefore allows you to
- enter a explanatory line of text that will be
- displayed together with the question mark.
-
- INPUT "What is this year´s profit "; x
- There are of course very many other simple
- BASIC commands that each achieve a certain
- effect. There really is no point in detailing
- each of them here, but look through the Command
- Reference section and find some more to try.
- Unless you are very unlucky with your choice,
- absolutely no harm can be done, but it is just
- as well to avoid using the commands BLOAD, PEEK
- and POKE for the time being.
- Here is an example of how to read the syntax of
- each command so that you know what MaxonBASIC
- expects.
-
-
-
- Reading the Syntax
-
-
- INPUT ["prompt"{;|,}] variable_list
- First of all, INPUT is the actual command and
- must be present to achieve anything at all.
-
- ["prompt"{;|,}]
- The square brackets ([]) around the whole entry
- indicate that its use is optional, you can
- leave it out and the syntax will still be
- valid. If you choose to use it though, you must
- enclose a message in double quotes ("") and
- finish the message with either a semi-colon or
- a comma. The curly brackets ({}) denote a
- choice with the vertical bar (|) separating the
- choices that are available in this case. In
- fact, using the semi-colon to end the prompt
- string adds a question mark to the end of the
- string, while using the comma will not add
- anything to the string.
-
- variable_list
- Finally, the INPUT statement must be finished
- with a list of variable names to which you want
- to assign data - this is not optional.
- With just these few commands that we have
- already learnt we can go a long way towards
- writing programs that show the real power of
- BASIC and in particular the way computers can
- handle repetitive and logical tasks with ease.
-
-
- The Heart of a BASIC Program
-
- Individual keywords can be strung together to
- make up quite long and complex commands. These
- make up the mechanics of your program. However
- over and above these the essence of most
- computer software lies in certain programming
- techniques that bring these commands to life,
- and structure them together in an intelligent
- and flexible way.
- There are really three very simple concepts
- that lie at the heart of every BASIC program.
- Once these are understood, learning how any
- program works will just be a matter of studying
- the small details.
- The three concepts are repetition, logical
- tests & decision making and passing control.
-
-
- Repetition - Loops
-
- Computers have certain strengths that make them
- powerful and extremely flexible tools. In some
- ways they are also rather stupid; they have to
- be told everything that they are expected to
- do. On the other hand they are able to perform
- these required tasks with great speed and, at
- least in theory, they will be able to repeat
- them ad infinitum without ever getting bored
- and making a mistake.
- One of the most important types of command we
- have available in most computer languages is
- known as a loop. This is the means by which we
- can make sure that commands can be repeated as
- many times as necessary without having to type
- them in over and over again.
- The most common type of loop seen in BASIC
- programs is the FORÉNEXT statement. This works
- by letting you set up a simple numeric variable
- as a counter which controls the number of times
- the following instructions are to be repeated.
- The NEXT command signals the end of the loop
- and tells the computer to move the counter onto
- its next value. This is what it can look like
- in practice:
-
-
- FOR x = 1 TO 6
- PRINT "Hello"
- NEXT x
- The result will be:
-
- Hello
- Hello
- Hello
- Hello
- Hello
- Hello
-
-
- Try it out.
- You can also specify the size of the jumps that
- the counter makes. Edit the first line to read:
-
-
- FOR x = 1 TO 6 STEP 5
-
-
- Do this by placing the cursor at the end of the
- first line and typing STEP 5.
- You should then see the results:
-
-
- Hello
- Hello
-
-
- The counter values can of course be set by
- other variables. Consider this short program:
-
-
- CONST start% = 4, finish% = 12
- jump = 2
- FOR x=start% TO finish% STEP jump
- PRINT x
- NEXT x
-
-
- We have introduced CONST to define one or more
- constant values and to give them names. This is
- very useful for writing easy-to-understand
- programs and you are encouraged to use CONST
- whenever you have values that will not change
- over the life of your program. Once defined,
- you cannot change the value of a named
- constant.
- One particularly useful feature of the FOR loop
- is that we can run one loop inside another
- using the technique known as nesting.
-
- The second loop runs through in its entirety
- every time the first loop executes just one
- step. Note that we have used indentation (i.e.
- adding spaces or tabs at the beginning of the
- line) to make the logic of the program more
- obvious. It is good programming practice to use
- indentation for statements within loops.
- In fact MaxonBASIC allows you to omit the
- variable name in the NEXT statement as in:
-
-
- FOR x = 1 TO 10
- PRINT x
- NEXT
-
-
- In this case the computer understands that you
- are referring to the counter variable x.
- Wherever an unspecified NEXT statement is
- found, the compiler will assume that it belongs
- to the last FOR in the listing.
- However, we do not advocate this omission of
- variable names with NEXT as it can cause
- unnecessary confusion and bugs.
- Loops are very useful things; they allow you to
- use the power of the language to automate all
- sorts of tedious tasks and achieve remarkable
- effects.
- If that was all there was to programming, our
- programs would be very mundane and predictable,
- doing essentially the very same tasks every
- time they were run. To make software more
- sophisticated and useful we have to introduce
- something else, the element of choice. Programs
- must be able to make decisions based on the
- information they have been presented with, ask
- the user what they are to do next and act on
- the reply. They must then produce different
- output in response to the value of certain
- variables.
-
-
- Decision Making
-
- Almost every program you write will use the
- ability of the computer to rapidly and
- repeatedly make logical tests and decide upon
- what action it should do next based on the
- results. A word processor decides whether to
- delete a word or insert a letter based on a
- test of what keys are being pressed; a space
- invaders game decides whether to ´fire a
- missile´ based on what is happening to the
- joystick - it knows whether to blow up an alien
- based on a test of the relative position of
- this missile on the screen and so on.
- There are two main statements that are used to
- make logical tests within BASIC. These are:
-
- IFÉTHENÉELSE and SELECT CASE.
-
- IFÉTHENÉELSE statements are virtually self-
- explanatory. They take the following form:
-
- IF something is true THEN
- do this
- ELSE
- do this instead
- END IF
-
- This really is no different to any (logical)
- decision we make in everyday life - the
- computer is just making its own assessment of
- the current state of affairs and then deciding
- which instructions to follow subsequently.
- The END IF command may be unfamiliar to people
- who have used older versions of BASIC.
- MaxonBASIC allows each set of instructions
- following the various parts of the structure
- (IF, THEN and ELSE) to cover several lines of
- the listing. END IF (note the space between END
- and IF) is therefore necessary to signal when
- all of the commands associated with the
- IFÉTHENÉELSE statement have finished, and where
- the remainder of the program is to continue.
- It is possible to omit the ELSE part of this
- structure, which is useful when you want the
- program to do something if a certain condition
- is true, but to carry on as normal otherwise.
- IFÉTHEN statements can be nested within one
- another to increase the range of choices using
- the keyword ELSEIF e.g.
-
- IF condition one is true THEN
- do instruction one
- ELSEIF condition two is true THEN
- do instruction two
- ELSEIF condition three is true THEN
- do instruction three
- ELSE do instruction four
- END IF
-
- As you can imagine it can get rather
- complicated for you to follow the argument and
- feel confident that the logic used really is
- correct but clear use of indentation helps
- greatly. Examples of IF statements follow
- shortly.
- A structure that can often be used as an
- alternative to IF is the SELECT CASE structure
- which is ideal for allowing the computer to
- make one from a very wide selection of choices
- depending on the results of the logical test it
- has made. Although the exact syntax of the
- command when you use it will be rather
- different, you can think of SELECT CASE as
- representing a situation like (in plain
- English):
-
- SELECT from the following
- In the CASE where this test is true
- do this
- In the CASE where the this test is true
- do this instead
- In the CASE where this test is true
- do something completely different
- In the CASE where something ELSE is true
- do this
- END SELECT
-
- (The END SELECT command is essential to let the
- computer know that it has reached the end of
- the instructions relating to the last CASE).
- Before we can go on and give working examples
- of these commands and their correct syntax, it
- is important to illustrate exactly how the
- computer can go about making logical tests.
-
- Logical Tests
- Computer logic resolves all things down to a
- simple test of ´true´ or ´false´. These two
- possible conditions can be made to represent
- almost everything you wish, from whether a
- switch is on or off to whether your bank
- account is in the black or in the red but, in
- the end, all the computer cares about is
- whether the test you have requested results in
- a ´true´ or a ´false´ result.
- BASIC uses the values of 0 for FALSE and -1 for
- TRUE. Why this is so would take an explanation
- of how BASIC calculates, and how it holds
- numbers in memory. We will be tackling these
- issues in more depth later but if you are ready
- for them now you have opened the manual at the
- wrong page.
- The main point for beginners to bear in mind is
- that, while the correct explanation of how
- computer logic works sounds both confusing and
- highly unlikely, in practice using it is a
- remarkably simple and obvious process.
- The use of logical tests in BASIC hinges around
- the following conditional symbols, known as
- relational operators, which express the
- criteria by which the computer is to determine
- whether the test is ´true´ or not.
-
-
-
- > greater than
- < less than
- = equal to
- <> not equal to
- >= greater than or
- equal to
- <= less than or
- equal to
- == almost equal to
-
-
-
- The last option, ==, will come as a
- surprise to anyone used to other versions
- of the language. It is used is to allow
- text comparisons that ignore any
- differences in the case of the two
- strings, and to allow comparison between
- two floating point numbers - which will be
- explained later - to ensure that a match
- is made despite small rounding errors
- during calculation.
- It doesn´t take a genius to figure out that the
- comparisons these make must be between two
- variables, or a variable and a constant -
- testing between two constants is pointless as
- it will give the same result every time
- (although this is occasionally useful to force
- a result).
- We can now look at a typical IFÉTHEN statement
- - Close your existing source code window and
- type this in:
-
-
- INPUT "What is your income this year"; income
- INPUT "What will be your costs"; costs
- IF income > costs THEN
- PRINT "Hooray!"
- PRINT "We´re in the money!"
- ELSE
- PRINT "Start packing your bags!"
- PRINT "I´ll book the boat to South America."
- END IF
-
-
- Providing different values for the income and
- costs will show exactly how the computer´s
- output reflects the result of the test. Try
- putting a FORÉNEXT loop round the outside of
- the program to try out 5 different sets of
- income/cost ratios.
- Note that, if you use multi-line IF statements,
- the IF, ELSE and END IF must be on lines by
- themselves.
- Here is an example using a SELECT CASE
- statement to show one version of the correct
- syntax. To maintain compatibility with as many
- versions of BASIC as possible this command
- structure has been implemented in a very
- flexible way and you are referred to the
- Command Reference section for a full list of
- the options.
-
-
- INPUT "A number, please";a
- SELECT CASE a
- CASE = 12
- PRINT "Number = 12"
- CASE > 20
- PRINT "Number is greater then twenty"
- CASE <= 4
- PRINT "Number is 4 or less"
- CASE ELSE
- PRINT "Number hasn´t met any of my
- conditions"
- END SELECT
-
-
- To extend the usefulness of the above
- relational operators we have the keywords AND,
- OR, XOR, EQV and IMP. These are used to compare
- two separate tests and to make judgements about
- their relative validity.
- The first two are again very easy to grasp as
- in the following examples:
-
-
- IF income > costs AND tax < profit THEN
- PRINT "Hooray!"
- END IF
-
-
- The expression will only evaluate as ´true´ if
- both conditional tests are themselves true.
-
-
- IF income > costs OR tax_rebate > 5000 THEN
- PRINT "Hooray!"
- END IF
-
-
- The expression in line 1 will evaluate as
- ´true´ if one or other or both of the tests are
- themselves true.
- XOR is a trickier one to define as it has no
- direct comparison in the English language. It
- essentially stands for eXclusive-OR which means
- that the expression will evaluate as true if
- one or the other half is itself true but not if
- they are both true together e.g.
-
-
- IF income > costs XOR deficit < max_tax_loss
- THEN
- PRINT "Hooray!"
- END IF
-
-
- EQV, short for EQuiValent, is used when two
- tests are to be made which need to give the
- same result, whether the result is true or
- false i.e.
-
-
- x = 1 : y=2
- IF x = 10 EQV y = 230 THEN PRINT "Yep"
-
-
- will print Yep because both comparisons give an
- equivalent result i.e. ´false´.
- IMP stands for ´is IMPlied by´ This is without
- question the most abstract of the logical
- tests. To complicate matters even further it is
- the only logical operator that puts a strong
- emphasis on the order in which the two subtests
- are listed. It can best be understood as a
- measure of whether or not the result of the
- second test can be implied by, or concluded
- from, the result of the first test.
- The rules are that:
- ¥ a TRUE result can be concluded from a
- preceding TRUE result;
- ¥ a FALSE result can be concluded from a
- preceding FALSE result;
- ¥ a FALSE result can be concluded from a
- preceding TRUE result;
- ¥ a TRUE result cannot be concluded from a
- preceding FALSE result.
- The premise is that it is possible to draw the
- wrong conclusions from correct assumptions, but
- it is impossible to draw the correct
- conclusions from wrong assumptions - try these
- out:
-
-
- x = 1 : y = 2
-
- IF x<2 IMP y<3 THEN PRINT "Yep" ELSE PRINT "No"
-
- IF x=2 IMP y=10 THEN PRINT "Yep" ELSE PRINT
- "No"
-
- IF x=1 IMP y=10 THEN PRINT "Yep" ELSE PRINT
- "No"
-
- IF x=2 IMP y=2 THEN PRINT "Yep" ELSE PRINT "No"
-
-
- The implications of all the above logical
- operators can be reversed by the use of the
- keyword NOT as in:
-
-
- IF NOT (x=10 AND y=12)
-
-
- and so on.
-
- Testing Text
- It is of course equally possible to make
- logical tests on text data. The relational
- operators we use to express the test are the
- same as with the numeric examples given above
- but the way in which the computer evaluates
- whether the result is TRUE or FALSE is rather
- more complex.
- Possibly the simplest to start with is to test
- whether two text strings are equal (=) or not
- equal (<>). Obviously this example:
-
-
- test$ = "FRED"
- IF test$ <> "BILL" THEN BEEP
-
-
- is straightforward.
- But what about operators such as greater than
- (>) or less than (<)? How can we say that one
- word or letter is ´greater´ than another?
- To understand the answer we will have to make a
- diversion into looking at the way computers
- store letters in their memory.
- Despite the way they look on screen, computers
- store letters in their memory as numbers. All
- modern computers stick to an American
- convention known as ASCII (which incidentally
- stands for American Standard Code for
- Information Interchange) whereby each letter
- has a certain number associated with it. By
- standardising things in this way it has made it
- possible for computers to talk to each other
- and send text such as Hello Jim without it
- coming out as ghJJm KPhZz.
- Note that all lower case letters have higher
- numbers than all the upper case ones. The
- digits (0-9) come before both. The letters with
- a value of 0-31 in the ASCII table are special
- control characters. Sending these, or a
- combination of them, to the screen or printer
- often produces a response such as changing some
- characteristic of the display, or type style,
- or moving the cursor.
- In a logical test, the first character of each
- of the two strings that are being compared will
- be tested - if one has a higher ASCII number
- than the other it will be regarded as
- ´greater´. If both characters have the same
- ASCII number the computer will move on to the
- next character in both strings.
- If both strings are the same for all of their
- common length except that one is longer than
- the other, the longer one will be regarded as
- greater rather than the shorter string.
- Note also that even a blank space is a
- character and it comes before all others (value
- 32 in the ASCII table). A leading space in some
- of the data is a common way in which text
- comparisons can become completely confused, and
- it can be a very difficult problem to spot.
- Perhaps it all sounds a little complex, but the
- encouraging thing is that in practice it is
- easier than it looks. Common sense will usually
- tell you what the outcome of any test between
- two strings will be. The only time it is likely
- to be as clear as mud is when punctuation and
- unusual characters such as , ¯, and § are
- compared, as these tend to occur in
- unpredictable places in the standard ASCII
- character set.
- The relational operator == is particularly
- valuable when making text comparisons, as it
- can be used to ignore any differences between
- the case of the letters being compared e.g.
-
-
- INPUT "Are you happy"; ans$
- IF ans$=="Yes" THEN PRINT "I´m glad!"
-
-
- Will give a glad message if you respond with
- YES, yes, Yes etc. but not if you answer No.
-
-
- Logical Loops
-
- We have so far seen how to get the computer to
- execute a series of instructions a set number
- of times as a loop. We have also seen how to
- make it decide, from a series of options, what
- it is to do next, based on a logical test.
- The situation often arises where the user
- simply cannot predict how many times a certain
- loop will be required to execute and it would
- be ideal if we could get the computer to use
- its logic to decide this for itself whilst
- running. MaxonBASIC provides several methods of
- doing just this, based on special loops that
- continue to execute until a logical test tells
- them to stop.
- (Note that many inferior BASICs which lack
- these facilities sometimes forced the user to
- insert a logical test within a FORÉNEXT loop.
- This test would force an unannounced jump from
- within the loop and end its execution when the
- true result was reached. Most authorities would
- agree that this is bad programming practice
- although it was often the best way of getting
- the job done under the circumstances. Unlike
- some languages, MaxonBASIC can handle such
- ´jumps´ without complaint, but the programs you
- write will be much clearer if you avoid doing
- so and use the following structures.)
- The three logical loops that we can use are
- known as the WHILEÉWEND, REPEATÉEND REPEAT and
- DOÉLOOP statements.
- The first one works like this.
-
- The WHILE loop
-
- WHILE conditional test is true
- do this
- do this
- WEND
-
- The WEND keyword simply signals the end of the
- instructions that are to be included within the
- loop.
- Here is an example:
-
-
- INPUT "What is your bank balance"; balance
- income = 50
- month = 1
- WHILE (balance>0) AND (income>49)
- PRINT "What is the income for month"; month;
- INPUT income
- PRINT "What are the costs for month"; month;
- INPUT costs
- balance = balance + (income - costs)
- PRINT "New balance is"; balance
- month = month + 1
- WEND
- PRINT "It´s time to look at getting a proper
- job!"
-
-
- Note that, in order to ensure that the WHILE
- loop is executed at least once, we have had to
- initialise income to 50 (>49) before the
- beginning of the loop.
- In fact, it would be better, therefore, to use
- a different type of loop, the DO loop, for this
- example and we shall now see why.
-
- The DO loop
- The DO loop actually has several permutations
- which make it a very much more flexible
- construction than the WHILE loop. In fact it
- even has an option that will completely
- simulate the WHILEÉWEND command. The various
- permutations include:
-
- DO
- this instruction
- that instruction
- LOOP UNTIL condition
- DO UNTIL condition
- this instruction
- that instruction
- LOOP
-
- Can you see that these constructs are similar
- to a WHILE loop? Are there any differences?
- Yes É a DO UNTILÉLOOP executes the instructions
- in the loop until the condition becomes true
- whereas a WHILE loop executes until the
- condition becomes false. Also DOÉLOOP UNTIL
- checks its exit condition at the end of the
- loop, not at the beginning. Thus, in the
- previous example, since we did not know the
- value of income at the start of the loop,
- perhaps we should have used a DOÉLOOP UNTIL
- loop, not a WHILE loop - can you re-write it?
- There are other permutations of DO:
-
- DO WHILE condition
- this instruction
- that instruction
- LOOP
- DO
- this instruction
- that instruction
- LOOP WHILE condition
-
- As we said above, the logic of the WHILE
- comparison is opposite to that of the UNTIL
- option:
-
-
- DO UNTIL x = 10
- and
-
- DO WHILE x <> 10
-
-
- will produce exactly the same effect.
- The most general form of the DO loop is:
-
- DO
- this instruction
- that instruction
- LOOP
-
- This command structure will continue to run and
- run unless there is a logical test inserted
- somewhere within it terminating in an EXIT DO
- or EXIT LOOP command; these two are
- interchangeable.
- It is again possible to nest such loops several
- times, and indeed to nest one type inside
- another.
- It is also possible to have conditional tests
- at both ends of a DOÉLOOP.
-
- The REPEAT loop
- The third type of logical loop is the
- REPEATÉEND REPEAT structure. This has the most
- in common with the final form of the DOÉLOOP
- that we have just seen, in that there is no
- builtin way for the loop to terminate beyond
- the inclusion of one or several EXIT
- statements.
- The difference between the two types of loop
- hinges on the fact that each REPEAT loop you
- create can be given its own name. Several such
- loops can be nested culminating in a series of
- logical tests with EXIT statements. Any EXIT
- statement can itself refer to the name of a
- given loop, but not necessarily the one that
- was most recently defined. In other words you
- can EXIT a named outer loop from within an
- inner one; very useful for aborting some task
- if a catastrophic error occurs.
- We advise the use of DOÉLOOPs wherever possible
- since they have a much more coherent structure
- - try to avoid REPEAT loops unless absolutely
- necessary.
-
-
- Passing Control Within a Program
-
- The effect of logical tests is to force the
- program to make a decision about which lines of
- the program are to be executed next. In other
- words the flow of the program is passed from
- one section to another.
- Most large programs contain sections that are
- only executed as and when certain conditions
- are met. A space invaders game for example will
- have a GAME OVER message that will only be
- displayed when the program has realised that
- you have had all of your missile bases
- destroyed. As long as you can continue playing
- unscathed, control of the computer will never
- pass to the end-game section of the program.
- In the above examples the logical tests have
- passed control to one or two lines of the
- program, for very simple results. However there
- is no reason why there should not be enormously
- long and complex sections of the program that
- are accessed in each case.
- There are two distinct mechanisms that we can
- use to cause the computer to move to another
- section of the program. These are jumps and
- subroutine calls. The difference between the
- two is that when the computer jumps to a
- different part of the program it does not
- bother to remember where it came from and it is
- not able, and does not try, to get back there
- unless you explicitly tell it where to go. By
- contrast, subroutines and sub-programs are self
- contained sections of the program that fulfil a
- specific task and then automatically return
- back to the next instruction following the one
- that first called them.
- In older versions of BASIC, versions that
- required the user to begin each line with a
- number, jumps were made by simply entering GOTO
- line numbers as in the following example.
-
-
- 10 LET x = 1
- 20 LET y = 20
- 30 LET x = x + 1
- 40 IF x = y THEN BEEP ELSE GOTO 30
-
-
- This example also shows how very primitive
- logical loops can be created - the program will
- jump between lines 30 and 40 until the test is
- passed as true.
- Although it is capable of running the above
- program, MaxonBASIC does not force the
- programmer to use line numbers. But in that
- case how would we signal to the program when it
- is to make a jump, and where it is expected to
- go to?
- The answer is through the use of line labels,
- which are essentially names that we give to
- chosen lines in the program, usually lines that
- start a certain routine. By making a jump to
- one of these names the same effect is achieved
- as with a line number jump but the listing is
- made much more readable. Line labels are
- entered by just typing the required name
- followed by a colon.
-
-
- maingame:
- .
-
- .
- IF missile_base = 0 THEN GOTO endgame
- .
- .
- endgame:
- BEEP
- PRINT "Game over."
-
-
- In older versions of BASIC, subroutines were
- similarly accessed by a call to a certain line
- number which was to be the beginning of the
- routine itself. The keyword that makes this
- call is GOSUB. Here is an example:
-
-
- 10 INPUT "What is your bank balance"; x
- 20 IF x >0 THEN GOSUB 100 ELSE GOSUB 200
- 30 INPUT "How much will your bills be this
- week"; z
- 40 IF z > x THEN GOSUB 200
- É
- 100 BEEP
- 110 PRINT "There will be no bank charges"
- 120 RETURN
- É
- 200 BEEP
- 210 PRINT "There will be bank charges"
- 220 PRINT "unless you pay some money in"
- 230 INPUT "How much can you pay in"; y
- 240 IF y < x THEN PRINT "Not enough I´m afraid"
- 250 END IF
- 260 LET x=x+y
- 270 RETURN
-
-
- The keyword RETURN is essential to signal the
- end of the current subroutine, otherwise the
- subroutine would carry on ad infinitum.
- The above example appears slightly laboured
- because in very short programs it can be
- difficult to justify the use of subroutines as
- separate entities from the main lines of the
- listing. In long and complex programs however
- they perform several invaluable roles.
- Firstly they allow the programmer to divide up
- his work into a series of logical modules, each
- one of which can be worked on, altered, tested
- and debugged in isolation. As well as making
- things easier for the author of the program,
- they also make the listing very much easier to
- follow and alter at a later date.
- As an extension of this philosophy, once a
- subroutine has been perfected it can be made
- part of a stored ´source library´ of routines
- which can, at any stage, be slotted into new
- programs that are under development. For
- example there may be a subroutine that plays a
- tune which you can use in any game you write,
- or you may have some lines which place a menu
- of options on a screen, or which reads data
- from a disk file.
- Another important use for them is to make the
- actual listing of your programs more compact
- and economical. Any program routines that are
- used several times within the same listing need
- only be typed once, and they can then be
- accessed by the appropriate subroutine call as
- often as necessary.
- MaxonBASIC will of course allow the use of
- simple subroutines as described above but in
- addition, as with GOTO, it is possible for the
- routine to be called by a name rather than by
- its line number, which of course makes the
- listing easier to follow.
- Avoiding numbers also makes it logistically
- simpler to merge many different library
- procedures together into a new program.
- Another improvement is that the RETURN command
- can be followed by a line number or label that
- will allow the program flow to be passed to yet
- another part of the listing.
-
-
- A Better Way; Sub-programs
-
- As well as standard subroutines, there is a
- much more satisfactory way of organising
- programs into modules which are called sub-
- programs.
- Sub-programs have three advantages over
- subroutines, which may not be appreciated by
- many programming beginners but will become more
- and more important as your skills increase
- together with the complexity of your programs.
- These are:
- ¥ local variables
- ¥ parameter passing
- ¥ recursion
- Each of these will be explained as we progress
- with the tutorial.
- The keywords used for defining sub-programs are
- SUB and END SUB. Once defined they can be
- CALLed from anywhere else in your program
- listing.
- If you have been paying attention until now,
- you should find it fairly easy to decipher the
- following exampleÉ
-
- Try typing this in and running it. It has
- deficiencies; it only works properly using the
- standard fonts; the sub-program should be
- passed, as two parameters, the point at which
- the text has been drawn and it should then work
- out where to put the box É but you see the
- idea.
-
-
- Note the LOCATE x,y statement, after
- Mainprogram:, which positions the cursor at row
- x, column y within the window, so that the next
- PRINT takes place there. The origin is 1,1 not
- 0,0 as it is for graphics statements.
- Here´s a chance to show off a useful feature of
- the editor; you often want to use a sub-program
- or a function in many different programs -
- after all, that´s one of the main reasons for
- coding them in the first place. You could group
- all your sub-programs together in one program,
- save it and ´include´ it in whichever program
- was going to use the sub-program, function etc.
- However, there is an easier way that you may
- wish to use sometimes - simply cut the sub-
- program from one window and paste it into
- another, here´s how:
- Position the cursor at the start of the REM
- statement, click and hold the button down. Now
- drag the mouse until you have marked all the
- text up to the end of the END SUB and release
- the mouse button.
-
-
- Now select Copy from the Edit menu; this copies
- the marked text into memory.
-
-
- Now open a new window (AN) and select Paste
- from the Edit menu. The complete sub-program is
- copied into your new window, ready for use.
- Back to sub-programs É
- It is not uncommon to find well written modular
- programs where the main body of the listing is
- no more than a series of calls to different
- subprograms as in the following:
-
-
- CALL start
- CALL input
- CALL output
- CALL end
-
-
- You can invoke a sub-program called fred either
- by using CALL fred or simply using the name of
- the sub-program, fred. In this way routines can
- be executed just by using their names, almost
- as if they were special BASIC keywords that you
- have written yourself. The Command Reference
- section gives more details. However, we would
- like to stress one point here:
-
- CALL fred (john) is not the same as fred (john)
-
- When using CALL, you must enclose the
- parameters within parentheses and they are then
- passed as variable parameters (see below).
- However, when not using CALL, enclosing
- parameters in parentheses forces the parameters
- to be passed by value. Don´t blame HiSoft. It´s
- historical!
- More of sub-programs later.
-
-
- Choosing where to go
-
- A useful command structure that allows us to
- program jumps to different routines in a very
- concise way is ON x GOTO/GOSUB. In this case x
- is a numeric variable that can contain a number
- generated by the program, or entered by the
- user. The command sequence tests the value of x
- (or rather the integer value of x - see later)
- and will jump to the xth entry in a list of
- subroutine names, line labels or line numbers
- that can follow the GOTO or GOSUB command. This
- list can be up to 56 items long and can mix
- line or subroutine names and numbers.
-
-
- Mainprogram:
- REM Other lines of the program
-
- PRINT "Data listed on screen or printer?"
- PRINT "Screen.......1"
- PRINT "Printer......2"
- DO
- BEEP
- INPUT answer
- LOOP UNTIL (answer = 1) OR (answer = 2)
-
- ON answer GOSUB screenprint, paperprint
-
-
- Again the example looks like a rather
- longwinded way to achieve a simple effect but
- in complex programs this command structure is
- invaluable. The chosen variable in your own
- program can be used as an indicator (in
- computer jargon: a flag) of what routines have
- been accessed or what choices have been made by
- the user and the program response tailored to
- fit.
- It is not possible to call sub-programs with
- this command; to do this we recommend you use a
- SELECT CASE structure with CALLs which would
- look like:
-
-
- Mainprogram:
- REM Other lines of the program
-
- PRINT "Data listed on screen or printer?"
- PRINT "Screen.......1"
- PRINT "Printer......2"
-
- DO
- INPUT answer
- SELECT CASE answer
- CASE 1 : CALL screenprint
- CASE 2 : CALL paperprint
- CASE ELSE BEEP
- END SELECT
- LOOP UNTIL (answer = 1) OR (answer = 2)
-
-
- In general, we would advocate the use of CASE
- over ON GOTO/GOSUB since it normally leads to
- clearer programs.
-
-
- Sub-programs
-
- As we have said above, sub-programs are much
- more powerful than old-fashioned subroutines
- and we encourage you to use them whenever you
- can.
- Sub-programs have the ability to define and use
- variables that are only valid within the
- routine itself, but which have no effect on
- other variables of the same name used elsewhere
- in other routines or within the main program
- body. These are what are known as local
- variables, because they are only recognised and
- used within one routine. They make it immensely
- easier to write and test procedures as
- independent modules without worrying about
- compatibility with others that do different
- tasks.
- Say that we want to write a sub-program that
- takes a text string and prints it ten times on
- the screen. Our sub-program may be of the
- following form:
-
-
- SUB Mul_Print
- FOR x = 1 to 10
- PRINT A$
- NEXT x
- END SUB
-
-
- Do not try entering this routine just yet - we
- will see shortly that it is not quite finished.
- Firstly, note that we have introduced a
- variable, x, that is used in the FORÉNEXT loop
- as the loop counter - it is obviously only
- needed while the loop is being executed and is
- therefore a prime candidate for being a local
- variable - we make it such by adding the
- statement STATIC x after the SUB definition. We
- have used the keyword STATIC to declare x as
- local to this sub-program - it will not be
- available outside the sub-program (but see
- SHARED later).
-
- If you are peachy-keen you may have
- noticed the keyword LOCAL in the Reserved
- Words list or the Command Reference and
- you may be wondering why we have not
- declared x as LOCAL. This is because
- STATIC x is more efficient on memory and
- runs faster - LOCAL x introduces a new
- variable every time it is encountered
- whereas STATIC x creates only one variable
- which is re-used. The main occasion when
- you might want to use LOCAL rather than
- STATIC is if you have a sub-program or
- function that calls itself and you need
- independent local variables within each
- call.
- Also, we have written the sub-program using the
- text variable name of A$. However to satisfy
- the requirements of flexibility and
- independence from the main program variables we
- have to find a way to tell the sub-program
- exactly what A$ represents when we call it. The
- situation may be that we may not have used that
- variable name in the main program, or even that
- we have used it for something completely
- different.
- Let´s write some code that might call
- Mul_Print:
-
-
- Main_Program:
- A$ = "Banana"
- B$ = "HiSoft = HIgh quality SOFTware"
- PRINT "MENU"
- PRINT "1. "; A$
- PRINT "2. "; B$
- INPUT x
- SELECT CASE x
- CASE 1 : choice$=A$
- CASE 2 : choice$=B$
- CASE ELSE choice$="Not given"
- END SELECT
-
-
- The next thing we want to do in this program is
- to make a call to the Mul_Print sub-program. We
- need to let this sub-program know that we want
- it to print choice$ rather than A$, even though
- we have used the name A$ in the actual
- Mul_Print routine. The SUB was possibly written
- months before and stored in a library.
- Our old type of subroutine detailed above will
- have been unable to allow for this necessary
- degree of flexibility. However when using sub-
- programs we can do it with ease thanks to a
- technique known as parameter passing.
- To use this we first have to alter the first
- line of our sub-program to contain not only the
- name of the procedure, but also the parameters
- it will expect to be given from the main
- program.
- In our example this would be:
-
-
- SUB Mul_Print(A$)
- STATIC x
- FOR x = 1 to 10
- PRINT A$
- NEXT x
- END SUB
-
-
- When we actually make the call to the sub-
- program from the main program we have to also
- include in that line the appropriate variables,
- numbers or text strings that we want each
- passed variable to represent.
- In our example this line would be:
-
- Mul_Print choice$
- Not surprisingly the parameters that are passed
- must match the parameters expected by the sub-
- program in number, type and order but they need
- not match with regard to the actual names used.
- The complete program would be:
-
-
- SUB Mul_Print(A$)
- STATIC x
- FOR x = 1 to 10
- PRINT A$
- NEXT x
- END SUB
-
- Main_Program:
- A$ = "Banana"
- B$ = "HISOFT = HIgh quality SOFTware"
- PRINT "Menu"
- PRINT "1. "; A$
- PRINT "2. "; B$
- INPUT x
- SELECT CASE x
- CASE 1
- choice$=A$
- CASE 2
- choice$=B$
- CASE ELSE choice$="Not given"
- END SELECT
- Mul_Print choice$
-
-
- Not particularly useful, but it illustrates the
- point. Note how the sub-program is defined
- before the main program - this is good
- programming practice, but not essential.
- Now try editing the main program to include a
- second option for choosing how many times the
- string is to print. The Mul_Print sub-program
- will have to have a second parameter entered
- into the opening line, say Mul_Num which will
- be used in the line:
-
-
- For x = 1 to Mul_Num
-
-
- Remember to put a second parameter in the call
- to the sub-program to pass the value for this
- variable that has been selected by the user.
- By default MaxonBASIC assumes that all
- variables that are declared or used by a sub-
- program are STATIC variables i.e. are local to
- the sub-program and will not affect or be
- affected by the values of variables of the same
- name elsewhere in your program. STATIC
- variables are zeroed when your program is first
- executed but are then left alone by MaxonBASIC
- - their values are held static until you change
- them within your program.
- However, even though STATIC is the default, it
- is advisable to explicitly declare any local
- variables as STATIC (or LOCAL) since this
- improves the readability and maintainability of
- your program. Also, if you have variable checks
- on (a compiler option), an error will be
- reported if you use variables in a sub-program
- or function that have not been declared.
- However there are situations where it would be
- valuable for the computer to create a new
- variable each time a sub-program is called. If
- you want MaxonBASIC to create a new variable
- for each sub-program call then you should
- declare the variable as LOCAL, not STATIC.
-
- There is also a way of letting a sub-program
- act on and even change the values of variables
- that are used by the main program and without
- these having to be passed to the subprogram as
- parameters. We do this by stating, before they
- are declared or used by the sub-program, that a
- certain variable name is to be SHARED.
- As you will be able to deduce from the example
- programs we have used so far MaxonBASIC does
- not force you to define exactly which variables
- belong in which categories. The compiler is
- able to deduce the effect that you are trying
- to achieve unless there is a mistake in your
- own logic. For that very reason it is good
- programming practice to work out and specify
- exactly which variables belong to which types
- in your program.
-
-
- SUB testproc
- SHARED x,y
- PRINT x, y , z
- x = x + 10
- y = y + 10
- z = z + 10
- END SUB
-
- Mainprogram:
- x = 10 : y = 20 : z = 50
- PRINT x, y, z
- testproc
- PRINT x, y, z
-
-
- This will produce the following output:
-
-
- 10 20 50
- 10 20 0
- 20 30 50
-
-
- which illustrates that x and y were usable, and
- capable of being changed, by the sub-program
- even though they were not passed as parameters.
- The third variable, z, was in fact treated as
- two entirely separate creatures because, by
- default, it was STATIC to the sub-program. x
- and y were created by, and belong to, the main
- program unless SHARED; z belongs exclusively to
- the sub-program.
-
- Remember, the default situation is that
- every variable used in a sub-program is
- regarded as STATIC unless specified
- otherwise. The use of variables that are
- SHARED between sub-programs and the main
- program should be treated with extreme
- caution since it is easy to introduce
- obscure bugs using SHARED variables - see
- the SHARED variables section in the
- Concepts chapter for an example.
- SHARED variables are not the only means by such
- a sub-program can pass information or changes
- back to the main program body and this brings
- us on to a discussion about Value Parameters
- and Variable Parameters.
-
-
- Value and Variable Parameters
-
- There are two different ways that you can pass
- parameters to and from sub-programs with
- MaxonBASIC; essentially you can either pass
- just the value of the parameter to the sub-
- program or you can pass a reference to the
- parameter. In the latter case the parameter is
- called a variable parameter because the sub-
- program can actually modify the value of the
- variable since it knows where to find it - all
- parameters passed to sub-programs are, by
- default, variable parameters. This provides
- another mechanism, along with SHARED variables,
- for sub-programs to communicate with the main
- program and each other. For example:
-
-
- SUB Strip_Spaces(a$)
- STATIC b$,i,j
- b$=""
-
- REM Find first non-space character
- i=0
- DO
- i=i+1
- LOOP UNTIL MID$(a$,i,1)<>" "
-
- REM Now copy rest of string to temporary string
- FOR j=i to LEN(a$)
- b$=b$+MID$(a$,j,1)
- NEXT j
-
- REM Copy back to passed string
- a$=b$
- END SUB
-
- test$=" HiSoft"
- Strip_Spaces test$
- PRINT test$
-
-
- Try this for yourself; it shows the use of a
- variable parameter to strip the leading spaces
- from a string variable. We have used a few
- string functions (like MID$ and LEN$) that you
- may not have seen before - don´t worry, they
- will be explained later.
-
- In fact, there is a built-in function
- called LTRIM$ which will strip leading
- spaces for you - see the Command
- Reference.
-
-
- MaxonBASIC allows you to override the
- default that a parameter is a variable
- parameter - simply enclose the parameter
- in parentheses in the call to the sub-
- program e.g. if we had used
- Strip_Spaces(test$) above, test$ would
- have remained as HiSoft.
-
- If, instead, you use CALL to invoke the
- sub-program and you want the parameter
- passed by value when it has not been
- declared as such in the sub-program
- definition then, again, enclose the
- parameter in parentheses, for example:
-
- CALL Strip_Spaces ((test$))
- The alternative to variable parameters is the
- value parameter where only the value of the
- variable is passed to the sub-program and the
- variable itself cannot be modified. To indicate
- that you want a variable to be passed by value,
- you should precede it with the word BYVAL or
- VAL in the sub-program definition.
- For example:
-
-
- CONST FALSE=0
-
- SUB Factors(BYVAL Number)
- STATIC i
- FOR i=2 TO Number/2
- IF Number MOD i=0 THEN PRINT i
- NEXT i
- END SUB
-
-
- DO
- INPUT i
- Factors i
- LOOP UNTIL FALSE
-
-
- There is no need to make Number a value
- parameter in this example since it is not
- modified within the sub-program - but value
- parameters are processed considerably faster
- than variable parameters and, in a calculation-
- intensive (albeit simple) sub-program like this
- one, speed can be of paramount importance.
- So it is advisable to define your parameters as
- value parameters unless you need them to be
- otherwise.
- Note also the use of CONST to define a constant
- FALSE that can then be used with the DOÉLOOP to
- loop forever. Type in this program and run it -
- when you get bored hold down Ctrl-C to break
- out of the program.
- Now for a little funÉ
-
-
- Recursion
-
- Sub-programs do of course have the ability to
- call other sub-programs in turn, or even to
- call themselves if necessary. The level of
- complexity of such inter-related calls can be
- enormous, yet the resulting listing will remain
- obvious and easy to follow because the
- procedure name can almost be regarded as a
- brand new keyword that does a certain job -
- contrast that with a similar situation using
- line numbers.
- The ability of a sub-program to call itself is
- known as recursion. This is an enormously
- useful and powerful programming tool that opens
- up whole new worlds of opportunity and in doing
- so flies completely over the head of 90% of
- computer users.
- Unfortunately the programs used to demonstrate
- the principle usually employ it to solve
- complex and obscure mathematical problems that
- are far from easy to follow. We are not
- intending to let you off the hook either - on
- the MaxonBASIC disk you will see a version of
- the infamous ´Towers of Hanoi´ program, called
- Hanoi.bas. This demonstrates the full power of
- recursion by solving the sort of horrific mind
- bending puzzle that most people cannot
- visualise anyway and you should certainly study
- it when you have finished working through this
- book.
- However, here is a procedure that demonstrates
- recursion, at least to the extent of proving
- that it really does work. Like many recursive
- problems the same or a similar effect can be
- achieved by the use of logical loops, but you
- will often find that using procedures in this
- way is often much more efficient in both speed
- and compactness of your program.
- Type this in:
-
-
- ´ The ForWarD sub-program. Draws a line of
- length
- ´ r in the direction, dir, of the ´turtle´,
- ´ from its current position
- SUB FWD(BYVAL r)
- SHARED curx, cury, dir
- STATIC newx, newy
- ´ Calculate the new x and y co-ordinates
- newx = curx + r * COS(dir)
- newy = cury + r * SIN(dir)
- ´ Draw the line
- LINE (curx, cury) - (newx, newy)
- ´ Update the (x, y) position of the turtle
- curx = newx
- cury = newy
- END SUB
-
- ´ Turn the turtle through r degress
- ´ i.e. simply change dir
- SUB RIGHT(BYVAL r)
- SHARED dir
- dir = dir - r / 180 * 3.1415926
- END SUB
-
- ´ Use FWD and RIGHT to draw a spiral
- ´ this sub-program is recursive, it calls
- ´ itself to draw successive, longer lines
- ´ to produce a spiral
- SUB spirals(BYVAL L, BYVAL A)
- FWD L
- RIGHT A
- IF L < 150 THEN spirals L + 1, A
- END SUB
-
- ´ Initialise the turtle and draw a spiral
-
- ´ You can try changing the numbers 9, 95 to
- ´ obtain different shapes
-
- main:
- curx = 160 : cury = 100 : dir = 0
- spirals 9, 95
- END
-
-
- Beginners may feel that they have been given a
- fairly rough ride over the last few sub-
- sections so let´s get back to some simpler
- BASIC concepts for a while.
-
-
- Functions
-
- Functions are an extremely important group of
- part of MaxonBASIC that encompass almost every
- type of task you can wish your computer to do,
- they can control graphics, text, calculation,
- logic, indeed there are very few programs that
- do not use functions of some sort in almost
- every line. Any attempt to define what
- functions do is therefore almost pointless -
- they can do anything and everything.
- What makes a function a function as distinct
- from any other element of BASIC is that, once
- called, it has to return some form of
- information, text or numeric data, to the
- original program. Most, but certainly not all,
- functions need some information to be passed to
- them from the main program to operate on.
- Because of their flexibility we will only
- briefly run through some of the different types
- of functions here, the majority of them will be
- covered as and when they come up under
- different logical headings in the tutorial and
- some will be left for you to discover in the
- Command Reference section.
-
-
- Mathematical Functions
-
- We have already seen how the use of different
- arithmetic signs, add, divide, multiply and
- divide can make your computer into a kind of
- calculator. To extend the usefulness of these
- MaxonBASIC comes with an extensive range of
- mathematical functions. COS and LOG are two
- examples:
-
-
- PRINT COS(45)
- y = LOG(x) : PRINT y
-
-
- Text Functions
-
- Most text functions are designed to perform
- operations on existing text strings. They will
- therefore be covered in depth in the section
- Strings and Things.
- Exceptions include two text functions that are
- designed to create new strings - SPACE$ and
- STRING$.
-
-
- A$ = SPACE$(10)
-
-
- will create a new string of ten spaces, which
- can be printed or assigned to a variable.
- STRING$ can be used to produce a string of
- specified length made up of a chosen character
- repeated:
-
-
- x = 23
- PRINT STRING$(x,"*")
- which will print:
-
- ***********************
-
-
- Miscellaneous Functions
-
- There are a wide selection of functions
- available that fit into no neat category, but
- just perform a useful job. Two simple examples
- are DATE$ and TIME$ which return the
- appropriate values from the computer for
- display within your own programs.
-
-
- PRINT DATE$
-
-
- may give the answer
-
-
- 22-04-1992
-
-
- Remember that a function, by definition, must
- return some sort of value or data to the
- program that called it.
-
-
- User Defined Functions
-
- MaxonBASIC has a very generous smattering of
- functions designed to provide you with a wide
- selection of useful tools for manipulating
- data. However it is impossible to predict or to
- cater for every possible eventuality that will
- come up. There will inevitably be times when
- you will want to use functions that do not come
- supplied. Fortunately you can then employ User
- Defined Functions to construct new routines to
- meet your own requirements.
- MaxonBASIC differs from many other versions of
- the language in that it allows the user to
- write complex multiple-line functions. These
- have many similarities with sub-programs. They
- can have parameters passed to them (and by
- definition must pass a result back to the
- calling program line). Also, they can use local
- and global variables and as such can easily be
- stored in a pre-written library of routines.
- The keywords used to set up and call a user-
- defined function are FUNCTION / END FUNCTION or
- DEF FN / END DEF / FN. As with sub-programs and
- logical loops the command EXIT FUNCTION / EXIT
- DEF can be used to trigger a jump from the
- function, e.g. if it has been passed a value
- that is outside of the range that you wish to
- permit.
- The name that is used to define a function as
- in the commands:
-
-
- DEF FNname or FUNCTION Cube
-
-
- is also the name used to call the function
- using the command:
-
-
- FNname or cube
-
-
- and is also used as a variable, within the
- function definition, which is assigned the
- value that is to be returned to the calling
- program line. Note that there are essentially
- two ways of defining a function; using the FN
- terminology or, more simply, using the FUNCTION
- keyword; we encourage you to use the latter,
- more modern method.
- Here is an example of a mathematical function
- that can be used to convert inches into
- centimetres.
-
-
- FUNCTION metric(a)
- metric = a*2.54
- END FUNCTION
-
- Mainprogram:
- Inches = 10
- CMs = metric(Inches)
- PRINT Inches; "inches
- equals";CMs;"centimetres"
-
-
- The following example of a text function can be
- used to strip trailing and leading spaces from
- any string. It employs one or two pre-defined
- text functions as building blocks; to follow
- these you must refer forward to the section on
- strings, or consult the Command Reference
- section.
-
-
- FUNCTION strip$(BYVAL A$)
-
- IF LEN(A$)=0 THEN EXIT FUNCTION
- WHILE LEFT$(A$,1)=" "
- Length=LEN(A$)
- A$=RIGHT$(A$,Length-1)
- WEND
-
- WHILE RIGHT$(A$,1)=" "
- Length=LEN(A$)
- A$=LEFT$(A$,Length-1)
- WEND
-
- strip$=A$
-
- END FUNCTION
-
-
-
- The above example is useful as an exercise
- but MaxonBASIC lets you strip leading and
- trailing spaces with LTRIM$(RTRIM$(A$))!
- If you use a function, declared using FUNCTION,
- before it is defined, you must tell MaxonBASIC
- that you are going to do this by using DECLARE
- FUNCTION name followed by its parameter list,
- at the front of your program. Otherwise the
- compiler may think that you are using an array
- name and not a function call e.g.
-
-
- DECLARE FUNCTION Cube (BYVAL x)
-
-
- PRINT Cube(5.6)
-
- FUNCTION Cube(BYVAL x)
- Cube=x*x*x
- END FUNCTION
-
-
- In general, it is a good idea to include all
- your sub-program and function definitions at
- the beginning of your program.
-
- Note that parameters passed to user-
- defined functions defined using DEF FN
- are, by default, value parameters - you
- can force a variable parameter by
- including the word VARPTR before the
- variable in the function definition. Also
- local variables within a DEF FN function
- are automatically assumed SHARED. This is
- all historical and we have included this
- behaviour in MaxonBASIC to be compatible
- with Microsoft QuickBASIC et al.
-
- Functions declared using the keyword
- FUNCTION do not suffer from this confusing
- behaviour towards parameters and local
- variables - they behave in exactly the
- same way as sub-programs; parameters are,
- by default, variable and local variables
- are, by default, STATIC. Therefore we
- advise you, most strongly, to use FUNCTION
- and not DEF FN, which is provided only for
- backward compatibility.
-
-
- More about Numbers & Text
-
- The ways that MaxonBASIC handles data,
- particularly numbers, is very much more complex
- than we have seen so far. This is not sadism on
- the part of the designers but is in fact
- essential (honest!).
- In every day conversation we all use numbers in
- a variety of ways and, most of the time, other
- people manage to work out exactly what we mean.
- For example you may say to someone ´I´ll be
- around in ten minutes´ and it is understood
- that you could in fact be eight, twelve or even
- twenty minutes. Conversely if you say ´I want
- to collect that ten pounds you owe me´ you will
- be rather unhappy to receive any less than
- that. The essential difference between the two
- is the precision of the figures we use and the
- implicit understanding of the person to whom we
- are communicating.
- The problem is that while people are able to
- use their experience to interpret what you
- probably mean, a computer takes everything much
- more literally. It will expect you to turn up
- in exactly 600 seconds to collect your 1000
- pence.
- As if that was not enough, even computers,
- which insist that you say exactly what you
- mean, do not always mean exactly what they
- appear to say. What would you make of a
- calculator that claimed that two plus two did
- not equal four. Not much probably, but it is
- actually possible for this to happen.
- Numbers that look quite simple to the user,
- such as ´4´, may in fact be stored as very much
- longer figures e.g. ´4.00012´. These slight
- aberrations from what the user sees, or means
- when typing in figures, result from minute
- rounding errors in the way that the
- calculations are performed internally.
- Obviously, this state of affairs can not be
- left to operate randomly. Small rounding errors
- of this sort, when added together or multiplied
- can eventually result in visibly different
- answers from that which is expected.
- We therefore have different ways of expressing
- numbers and numeric variables in MaxonBASIC
- that will control the degree of precision that
- you want the calculations to work to, and can
- force numbers to change their internal format
- to ensure that they achieve the desired result.
- The most important distinction is between
- integer and floating point numbers. An integer
- number is a whole number, i.e. there can be no
- decimal fraction. By forcing the computer to
- use integer numbers we can ensure that all
- calculations produce the result that we would
- expect, 2+2 really does equal 4. Integers are
- particularly useful when performing financial
- calculations where it is important that the odd
- penny does not go astray.
- Unfortunately, for unimportant reasons which
- have to do with the way that computers work,
- integer numbers usually have to fit within the
- range +32767 to -32768. In order to maintain
- compatibility with programs that run under
- other versions of BASIC, the MaxonBASIC
- recognises and uses the ordinary integer type
- and the associated commands that allow
- variables to be assigned as integers. However
- this version of the language has also been
- extended to also allow long integers, whole
- numbers in the range 2147483647 to -2147483648.
- Floating point numbers are any numbers that
- have a fractional part, i.e. there is a value
- after the decimal point. Again there are two
- different types of these numbers - single and
- double precision numbers.
- Floating point numbers are often displayed
- using scientific notation consisting of a fixed
- point number (the mantissa) followed by a
- letter E and then an integer which is the
- exponent. To convert this notation to a normal
- format you have to multiply the mantissa by ten
- to the power of the exponent.
- Single precision floating point numbers are
- accurate to seven digits in the mantissa while
- double precision numbers are accurate to 16
- digits in the mantissa. The exact ranges for
- these numbers are given in the Concepts
- chapter.
- For small number values, where there is no
- ambiguity in the precision, numbers will be
- displayed in the normal form. For large numbers
- scientific notation will be used on screen.
- Floating point numbers, and in particular those
- with double precision, use more memory and are
- slower to calculate than long integers, long
- integers are slower and use more memory than
- integers. However the power and speed of
- MaxonBASIC together with the large amount of
- available memory on the Amiga range means that
- these problems are much less noticeable than on
- other micros.
- You will have seen by now that MaxonBASIC does
- not force you to use any of these number format
- commands. As with many other commands, the
- language assumes a default setting of single
- precision if your exact requirements are not
- specified. There are also several associated
- commands that allow numbers of one type to be
- converted to another, for calculation or
- display.
- It is possible to denote explicitly which type
- a number or numeric variable belongs to by the
- use of a certain suffix.
-
- The % character denotes an integer.
- The & character denotes a long integer.
- The ! character denotes a single precision
- numbers.
- The # character denotes a double precision
- numbers.
- The suffix can be given as part of a number as
- in:
-
- x = 234%
- or as part of the variable name in which case
- that particular variable is unable to store
- data of the inappropriate type:
-
- x! = 2.34
- Constant literals, i.e. those that are not
- assigned to variables and which therefore will
- not change during the running of the program
- can again be integer, long integer, single or
- double precision floating point.
- Of course any number or variable that looks
- like an integer can be forced to be stored
- internally as a floating point number by use of
- the appropriate suffix. A number or variable
- that has a fractional part can be forced to be
- an integer by assigning it to a variable with
- the % or & suffix and if this is done the
- number will be rounded to the nearest integer.
- In the course of a calculation all numbers are
- converted to the same format as the highest
- precision number used anywhere in the current
- operation. The answer is also returned in a
- form that matches that precision. For example
- in the line:
-
-
- x& = 100000& + i%*i%
-
-
- i%*i% is evaluated as an integer and will
- overflow if i% is greater than 181. The result
- is added to 100000& and this result is then
- turned into a long integer.
- If an integer number, assigned to an untyped
- variable, undergoes a calculation such that it
- is converted to a number with a decimal
- fraction, i.e. the variable value is
- automatically converted to floating point. If
- the number is assigned to a typed variable the
- result of the calculation will be amended to
- fit that type.
- There are also several associated commands that
- allow numbers of one type to be converted to
- another, for calculation or display, or which
- control the type of number a variable is
- capable of holding.
- The following commands can be used to predefine
- what types of data a given variable name will
- store. They work by specifying the range of
- letters that are to begin the variable names
- for a given data type.
- For example:
-
-
- DEFDBL A-C, F
- will mean that all variables that begin with
- the letters A, B, C and F will all be assigned
- double precision values even though in the
- actual statement that gives the value to the
- variable the number could look like single
- precision or even an integer, without any #
- sign.
-
-
- DEFSNG range
- will predefine a range of variable names to
- take single precision numbers,
-
-
- DEFINT range
- will define them to take integers and
-
-
- DEFLNG range
- to take long integers. You can also use
-
-
- DEFSTR range
- to define variables to hold strings; this
- allows you to dispense with the $ suffix for
- the relevant string variables although, of
- course, you must still include the $ for MID$,
- LEFT$, LTRIM$ etc.
-
- All of the above definition commands are useful
- for freeing you from the need to explicitly
- define a variable type as it is being used, but
- they can be over-ridden by the use of the data
- suffixes described above. They are particularly
- valuable for catching input from the user that
- is required to be of a particular numeric type.
- There are a suite of commands that change the
- internal format of a given numeric variable
- into another type.
-
-
-
- CSNG(x)
- converts x to a single precision number,
-
-
-
- CDBL(x)
- converts x to a double precision number,
-
-
-
- CINT(x)
- converts x to an integer and
-
-
-
- CLNG(x)
- converts x to a long integer. In both of the
- latter cases the fractional parts are rounded
- to the nearest integer. Try this:
-
- x=22/7
- PRINT CSNG(x), CDBL(x), CINT(x), CLNG(x)
-
- CLNG is useful for promoting the result of a
- short integer calculation. As we said above,
- 100000& + i%*i% will overflow if i% > 181 but
- 100000& + CLNG(i%)*i% will allow a much wider
- range of values for i%.
- The following commands are functions that act
- on a given variable, to return the integer part
- of that variable, although as you can see there
- are subtle differences in the way they work.
- These functions can be used to assign the
- integer part to a new variable, to print it on
- the screen or to allow it to be used in a
- calculation.
-
-
-
- FIX(x)
- returns the truncated integer part of the
- number, x, i.e. if x is 1.2, FIX(x) returns 1.
- Similarly if x is 22.99, FIX(x) will return 22
- - it always rounds down with positive numbers.
- For negative numbers FIX still truncates the
- figures such that the overall effect is one of
- rounding up. If x is -22.99, FIX(x) will return
- -22.
-
-
-
- INT(x)
- returns the largest integer less than or equal
- to x. For positive numbers the effect is the
- same as FIX(x) but for negative numbers INT
- rounds down. If x is -22.99, INT(x) will return
- -23.
- Finally there are two special arithmetic
- operators - MOD and \ (backslash) which are
- used for integer division.
- In an arithmetic expression such as 20.4\5.2
- the backslash command stands for integer
- division such that both numbers are rounded to
- the nearest integers before the division takes
- place. The answer is also an integer value.
- The keyword MOD returns the remainder of an
- integer division as an integer. 33.2 MOD 5
- would return the value 3.
-
-
- Yet More Numbers - Bases
-
- There is one more aspect of the way that
- numbers are stored and used that needs to be
- covered. In conversation we use exclusively
- decimal numbers, each column in a large number
- represents ten times the number to the right.
- This is known as base ten arithmetic. However
- there is no reason why we have to be restricted
- just to that system.
- In their deepest darkest parts computers work
- exclusively in binary or base two arithmetic.
- Binary digits are either on or off and these
- two available options are used to build up
- larger and larger numbers. Each column in a
- large number represents twice the column to the
- right of it. In binary arithmetic 0 stands for
- 0, 1 for 1, 10 for 2, 11 for 3, 100 for 4, 101
- for 5, 110 for 6, 111 for 7, 1000 for 8 etc.
- However binary arithmetic soon gets unwieldy
- for people to use as the numbers increase in
- length rapidly, and are almost impossible to
- identify by just casual inspection. Programmers
- therefore tend to use the larger base eight
- (octal) arithmetic or base sixteen
- (hexadecimal) arithmetic. Because eight and
- sixteen are both powers of the number two, both
- octal and hexadecimal numbers have much more in
- common with the way that computers actually
- work than ordinary decimal numbers, and allow
- us to see patterns in the data that are
- meaningful to the computer.
- Because these number bases are usually used for
- direct manipulation of the computer memory or
- similar, and would hardly ever be used for
- other calculations, we do not make provision to
- use fractional parts of numbers expressed in
- octal or hexadecimal - they are all expressed
- as the equivalents of decimal integers.
- The command
-
-
- OCT$(x)
- will convert the (rounded) integer part of the
- number x to its octal equivalent. The result is
- stored as a string variable to avoid ambiguity,
- i.e. to ensure that calculations can not be
- attempted directly with octal numbers.
-
-
- HEX$(x)
- provides a similar conversion to hexadecimal.
- We have a problem with hexadecimal numbers that
- does not crop up in any base less than ten. We
- need a system for expressing numbers in the
- range 10-15 with just one figure. The
- convention used to do this is to use the letter
- A to stand for 10, B for 11, C for 12, D for
- 13, E for 14 and F for 15. So 8 = 8, B = 11, 10
- = 16, 15 = 21, 1A = 26 and FF = 255.
- Note for example that the total number of ASCII
- codes range from 0-255 and 255 is the binary
- number 11111111, and the hexadecimal number FF
- (both of which look much more significant than
- 255). This demonstrates how using other bases
- can be helpful in denoting meaningful numbers.
- MaxonBASIC allows the use of prefixes &B, &H
- and &O (O as in ÒOhÓ rather than ÒZeroÓ!) for
- specifying binary, hexadecimal and octal
- constants respectively - see the Concepts
- chapter for a full discussion of these
- different base constants.
- Having broached the issue of how computers
- store and use numbers internally, it is
- probably worth pushing on with the subject as
- some terms will inevitably come up in later
- parts of the tutorial. The following brief
- explanation is not essential reading at this
- stage but will become increasingly important as
- your programs become more sophisticated.
-
-
- How Computer Numbers Work
-
- Computers store all numbers and data internally
- in units known as bytes. A byte is an eight
- digit binary number that ranges from 00000000
- to 11111111 which is 0 to 255 decimal or 0 to
- FF in hexadecimal.
- Each digit in the binary representation of the
- number is known as a bit, this is short for
- Binary digIT. There are therefore eight bits to
- the byte.
- However as microcomputers have become more
- sophisticated and powerful this relatively
- small size of data has become something of a
- bottleneck to performance. Routines that needed
- to work on large numbers for example had to
- retrieve the data in small ´byte sized´ pieces,
- reconstruct the number in question, act on that
- data, break down the result into small pieces
- again and send it back into the memory. Most
- computer languages perform all of these tasks
- invisibly and the user knows little or nothing
- about it but there was an inevitable penalty in
- speed.
- For more rapid movement and manipulation of
- data there has developed a need for larger data
- ´packets´. As well as the byte we now have the
- larger two byte equivalent, the sixteen bit
- word and the four byte equivalent, the thirty-
- two bit long word.
- Within MaxonBASIC, integers are held in 16 bits
- and long integers in 32 bits. These give the
- numbers -32768 up to 32767 for integers and -
- 2147483648 up to 2147483647 for long integers.
- The reason that integers do not give 0 to 65535
- is that it is generally more useful to use
- signed numbers rather than unsigned although
- some languages do give you the ability to
- choose between signed and unsigned integers.
- Using signed integer arithmetic means that, in
- any integer, if the most significant (the
- leftmost bit) is set to 1 then the number is
- negative.
- Remember, it is perfectly possible to program
- in MaxonBASIC without concerning yourself with
- any of these details. It is only when starting
- to manipulate the memory of the computer
- directly that they will become important.
-
-
- Using Logical Operators in Arithmetic
-
- We have already seen how logical operators
- function to enable tests to be made between two
- different situations. The way these actually
- work internally is based on comparisons between
- the electronic patterns of two binary numbers -
- bitwise comparisons. In the case of a logical
- test the numbers that are usually compared are
- -1 (or another non-zero number) and O standing
- for true and false. Depending on the particular
- type of logical test that is made, the results
- of the comparisons will themselves resolve to a
- figure that will signify either true or false
- and the flow of the program will be altered in
- response.
- You can also use these logical tests in
- expressions; the two operands will be converted
- to integers (or long integers) and then into
- binary and compared, bit by bit, according to
- which logical operator you are using, to obtain
- the result.
- The following table shows the outcome of the
- comparison of each bit for the different
- logical operators:
-
-
-
- 1 and 0 and 1 and 0 and 1
- 1 0 0
- NOT 0 1 0 1
- AND 1 0 0 0
- OR 1 0 1 1
- XOR 0 0 1 1
- IMP 1 1 0 1
- EQV 1 1 0 0
- The type of comparisons that are made need not
- be confined to just true and false however,
- they can be used in just the same way to
- compare and modify two different binary numbers
- such as 10010011 and 11011110. They can
- therefore be used in the following way, for
- example:
-
-
- PRINT 162 AND 48
-
-
- will be calculated by bitwise-ANDing the two
- binary representations of these integers as is:
- 162 AND 48 is
-
-
-
-
- 00000000 10100010 AND
- 00000000 00110000
- _________________
- 00000000 00100000 = 32
-
-
- Note that we show, and calculate with, the full
- width (16 bits) of the binary representation of
- the integer - this is particularly important
- when using the operators NOT, EQV and IMP which
- may change a 0 bit to a 1 bit and thus often
- turn a positive number into a negative number.
- See if you can predict the outcome of this
- program before you run it :
-
-
- SUB L_Table(VAL x,y)
- REM Set tab width to 9
- WIDTH 80,9
- PRINT "X","Y", "X AND Y", "X OR Y", "X XOR Y",
- PRINT "X EQV Y", "X IMP Y", "NOT X"
- PRINT
- PRINT x, y, x AND y , x OR y, x XOR y,
- PRINT x EQV y, x IMP y, NOT x
- PRINT
- END SUB
-
- j=33
- FOR i=4 TO 7
- CALL L_Table (i,j)
- NEXT i
-
-
- These logical transformations are not of
- obvious use to the novice programmer but are
- extremely important for use in graphics work.
- XOR in particular has a useful effect that
- fairly easy to demonstrate.
- Consider this:
-
- 162 XOR 48 gives:
-
- 00000000 10100010 XOR
- 00000000 00110000
- 00000000 10010010 = 146
- Now what about 146 XOR 48?
-
- 00000000 10010010 XOR
- 00000000 00110000
- 00000000 10100010 = 162
-
-
- So, XORing a number with a constant and then
- XORing the result with the same constant gives
- us the original number. Because of this
- feature, XOR is used a in computer graphics to
- produce ´non-destructive´ animation i.e. to
- allow pictures to move around on a screen
- without permanently obliterating what was in
- the background. First a certain graphics
- pattern is XORed onto the screen memory and
- hence displayed. XORing the same pattern a
- second time restores exactly the image that was
- there previously. The pattern is then
- repositioned slightly and XORed again to give
- the impression of movement across the screen.
- The ability to XOR graphics images is
- implemented in the PUT statement, as shown in
- the following example.
-
-
- REM Simple use of GET and PUT
-
- DIM Amiga%(1000)
-
- ´ Draw a box starting at (100, 50)
- LINE (100, 50) - (150, 150), 1, BF
-
- ´ Get entire box
- GET (100, 50) - (150, 150), Amiga%
- CLS
- FOR i = 0 TO 100 STEP 5
- PUT (i, i), Amiga%, XOR
- SLEEP
- PUT (i, i), Amiga%, XOR
- SLEEP
- NEXT i
-
-
- Type in this program and run it. Now repeatedly
- hit any key, as quickly as you like, to watch a
- black box appear and disappear while moving
- across the screen.
- You might like to save this program. Make sure
- you have a disk in drive DF0 with enough space
- on it (or room on your hard disk) and then
- select Save asÉ from the Project menu.
- A file selector will appear (this is the WB3
- ASL file selector, yours may be slightly
- different).
-
-
- Type in the name you want to call your program
- (say Amiga.bas). Now click on Save or hit
- Return.
-
-
- Strings and Things
-
- Strings, or text variables, differ from numbers
- in that, at least as far as the computer is
- concerned, there is no logical relationship
- between one character and the next - they are
- just a collection of letters and numbers
- ´strung´ together.
- Unlike decimal numbers where each character
- position signifies a tenfold relationship with
- the one to the right, strings cannot be used in
- calculations. This is true even when they look
- like numbers.
- At times this distinction is very valuable - in
- calculating programs such as spreadsheets for
- example you can ask for a total of all numbers
- in a large block of data without worrying that
- the computer will also include bank account or
- telephone numbers as well.
- However there are certain manipulations we can
- do with strings that are impossible with
- numbers. Long strings can be built up from
- shorter ones by a process called concatenation,
- which really just means adding them together -
- try this:
-
-
- A$="Hello"
- B$="John"
- C$=A$+" "+B$
- PRINT C$
-
-
- This can be very useful for creating complex
- display layouts for example by making strings
- of tab characters - CHR$(9) - and by using
- carriage return codes - CHR$(13).
- Dividing strings into smaller portions is known
- as string slicing. The following functions all
- return strings that are at most equal to, or in
- some way smaller than, the original that they
- were given as an argument.
-
-
- LEFT$(string$,x)
- will return the first x characters counting
- from the left of the string.
-
-
- RIGHT$(string$,x)
- will return the first x characters from the
- right of the string.
-
-
- MID$(string$,a,x)
- returns a string of x characters long starting
- from the position a in the original (the
- required length, x, can be omitted in which
- case the entire remainder of the string is
- returned).
- MID$ can also be used to alter the data held
- within a string by specifying a portion that is
- to be replaced with a second string using the
- syntax:
-
-
- MID$(string$,a,x)=string2$
-
-
- This will replace x characters from string,
- starting at position a, with the first x
- characters from string2.
-
-
- INSTR(a,string$,string2$)
- will search for the first occurrence of string2
- within string starting optionally from position
- a. If the second string is found the function
- returns the position of the first character of
- that string. Try this:
-
-
- SUB Search (BYVAL A$)
- IF INSTR(1,A$,"HiSoft")<>0 THEN
-
- PRINT "That´s what we like to see!"
- ELSE
- PRINT "Where´s the HiSoft?"
- END IF
- END SUB
-
- DO
- INPUT "Gimme some words, please";Test$
- Search Test$
- LOOP UNTIL Test$=="END"
-
-
- The opposite of INSTR is RINSTR; this searches
- backwards through a string starting at the end.
- See if you can work out what this does:
-
-
- INPUT a$
- DO
- i-RINSTR(a$," ")
- IF i=0 THEN EXIT LOOP
- PRINT MID$(a$,i+1); " ";
- a$=LEFT$(a$,i-1)
- LOOP
-
-
- These commands can be used in conjunction with
- each other to build up more complex string
- manipulation expressions. They work well in
- conjunction with the function:
-
-
- LEN(string$)
- that returns the length of the string in
- question.
-
- LSET and RSET can be used to place a string of
- text within a string variable of greater length
- such that the smaller string is assigned flush
- with either the left hand end (left-justified)
- or the right hand end (right-justified) of the
- larger. For these commands to work you must
- first create a larger string of the required
- size and the easiest way to do this is to use
- either the SPACE$ or the STRING$ commands. LSET
- and RSET are normally used when using files and
- FIELDed variables but can be used to left- and
- right-justify any string.
-
-
- A$=STRING$(30," ")
- B$="HELLO!"
- PRINT A$
- PRINT B$
- RSET A$=B$
- PRINT A$
- LSET A$=B$
- PRINT A$
-
-
- To illustrate the use of some of the above
- functions here is one that can be used as a
- complement to RSET and LSET to centre one text
- string within another.
-
-
- FUNCTION centre$(main$,insert$)
- STATIC a,b
-
- a = LEN(main$)
- b = LEN(insert$)
- IF b >= a THEN
-
- FNcentre$ = LEFTS(insert$ ,a) : EXIT
- FUNCTION
- END IF
- c = (a-b)\2 ´ integer division
- MID$(main$, c+1) = insert$
- centre$ = main$
- END FUNCTION
-
- DO
- INPUT "A word";a$
- INPUT "Another word";b$
- PRINT centre$(a$,b$)
- LOOP UNTIL a$=="END"
-
-
- UCASE$ and LCASE$ convert all letters within a
- given string into upper case or lower case
- respectively. These are useful routines for
- tidying up the response given by a user:
-
-
- DO
- INPUT "What is your name"; A$
- LOOP UNTIL A$<>""
- B$ = UCASE$(A$)
- PRINT "HELLO "; B$
-
-
- Of course punctuation and numbers within the
- string remain unchanged.
-
-
- Numbers to Text and Back Again
-
- We have already touched on the subject of how
- letters are actually stored internally in the
- computer as numbers. These are known as ASCII
- (American Standard Code for Information
- Interchange) numbers and every letter or
- character that you can type with your Amiga
- will have its own internal ASCII number.
- Obviously it is vitally important that the
- computer knows at any one time whether the
- numbers it has stored in its memory are
- actually to be regarded as numbers or whether
- they really represent text.
- Say for example that you have stored on a file
- somewhere your telephone number 0525718181. It
- will be essential that your programs are aware
- that this is actually a text representation of
- a number rather than a true number. It cannot
- be multiplied by any other figure, divided,
- assigned to a numeric variable, converted to
- double precision and so on, and in particular
- it should never be used to calculate your
- taxable income by your home accounts program!
- It is to avoid such ambiguity that computer
- languages such as MaxonBASIC insist that text
- variables are denoted by the suffix $ and the
- text strings themselves are enclosed in quotes.
- However there are situations where it is
- important that the programmer has control over
- the way that the internal numbers are handled.
- It is possible to convert numeric variables to
- text, and vice versa, and we shall see that
- there are certain advantages to doing so.
-
- Text as numbers - the ASCII codes
- Although text is always stored in memory as
- ASCII numbers the computer keeps track of which
- variables really represent letters and need to
- be converted to such before displaying them on
- the screen. There are however circumstances
- where it is valuable for the programmer to be
- able to access these numbers directly and
- decide what to do with them.
- A typical situation may be where text data is
- stored in an unstructured way in memory, which
- could happen if it has been imported from
- another computer through one of the expansion
- ports. The actual data read and stored will be
- the ASCII number equivalents of that text.
- At a later stage if you wish to display the
- information on screen you will have to
- explicitly signal to the computer that you want
- the data to be interpreted as letters rather
- than as numbers - unlike defined variables the
- computer will be unable to guess what each
- piece of data is to represent.
- The keyword we use to convert a stored ASCII
- number to its text equivalent is CHR$(). Within
- the brackets we should put either a number or a
- numeric variable name. The computer will then
- convert this number to text using its internal
- ASCII table.
- The following short example will illustrate the
- way that the conversion of ASCII numbers to
- text works:
-
-
- a = 72
- b = 69
- c = 76
- PRINT CHR$(a);CHR$(b);CHR$(c);CHR$(c);CHR$(79)
-
-
- which will produce the message HELLO.
- It may seem a cumbersome way of doing things,
- but storing text in this way can be extremely
- useful. In particular it is valuable when you
- want to print or display characters that cannot
- actually be typed at the keyboard.
- As well as producing some of the more unusual
- characters, different ASCII numbers can be used
- by your programs to trigger special effects.
- Data files created by word processors, text
- editors and the like will contain ASCII
- numbers. Similarly all information exchange
- from the keyboard to the computer, from the
- computer to the printer, from the computer to
- the disk drive and from the computer to another
- computer will be as ASCII information. However
- what happens to that information when it
- arrives depends on the program that is running
- and on the computer´s operating system.
- For example, when ASCII codes are sent to the
- printer they do not all appear on paper. Some
- are regarded as control codes that instead
- trigger some sort of special effect. One such
- special effect code is ASCII number seven which
- produces a beep, either from the computer or
- the printer depending on where the code has
- been sent.
- Another very important control code number is
- ASCII 27 which is known as the escape code.
- Most printers use this to signal the start of
- some command sequence that will produce a
- different type style such as bold or enlarged
- print or some other effect.
- Many software programs will use their own
- routines to catch certain ASCII codes coming
- from the keyboard and to use them to trigger
- actions. One might do a simple test on which
- letter has been sent, but again ASCII codes are
- usually more flexible as it is possible to
- select unusual numbers that can only be ´typed´
- by some combination of letters such as Ctrl-X
- which in the Amiga keyboard produces the
- character number 24. Alternatively an unusual
- code or sequence of codes can be assigned to
- one of the ten function keys.
- One of the most common and important ASCII
- control codes you will ever use is number 10
- which is the code for line feed. This is the
- code which is sent whenever you press the
- Return key on your keyboard and signal the end
- of one line and the start of the next when you
- are typing e.g. using your MaxonBASIC editor.
- These codes are also extremely useful for
- controlling the display of information on the
- screen. Say you want to define the text
- variable ADDRESS$ to produce this output:
-
-
- John Smith
- 22 Long Lane
- Newtown
-
-
- You can achieve this by using, all on one line:
-
-
- ADDRESS$="John Smith"+CHR$(10)+"22 Long
- Lane"+CHR$(10)+"Newtown"
-
-
- There is an associated keyword which will
- return the ASCII number for any given letter or
- text variable. This command is ASC(). Example:
-
-
- PRINT ASC("A") : PRINT ASC("*")
-
-
- Sometimes the keyword ASC() is not appropriate
- because it always converts the characters to
- their ASCII table equivalent rather than to
- what we would regard as their direct numeric
- equivalent.
- For example the text character 9 has the ASCII
- value of 57. The following line would therefore
- give the answer of 570.
-
-
- x = ASC("9") : PRINT x * 10
-
-
- What we need in this case is VAL. VAL searches
- a string expression for anything that can be
- interpreted as a number, integer or floating-
- point.
- Try these out:
-
-
- x = VAL("9") : PRINT x * 10
- PRINT VAL("180 High Street North")
- PRINT VAL(" -256+40=-216")
- a$="26.04 - the price plus VAT")
- PRINT VAL(a$)
-
-
- VAL stops looking for a number as soon as it
- encounters something (apart from a space, tab
- or end-of-line) that it thinks cannot start a
- number.
-
- Numbers as text
- Converting numbers to characters is essential
- whenever they are to be incorporated into a
- long string of text, or imported into a text
- data file such as one produced by a word
- processor etc. There are however other possible
- advantages in making the conversion.
- We have already seen how text strings can be
- sliced into smaller pieces, or joined together,
- and in several ways manipulated in a very
- different manner to numeric variables. There
- are often occasions where it is useful to be
- able to do the very same things to numbers.
- We have already seen above how to take a string
- and extract a number from it using VAL; the
- converse of this is where you want to convert a
- number into a text string - for this you use
- STR$. STR$ inserts a leading space or a minus
- sign, if the number is non-zero.
-
-
- a=1066 : b$=STR$(a)+" and all that!"
- PRINT b$
- big=-98765.43 : b$=STR$(big)
- PRINT LEFT$(b$,3);",";RIGHT$(b$,LEN(b$)-3)
-
-
- More Ways to Store Variables and Data
-
- Computers are used all around us today, in
- almost every profession, business or service
- you can name, to store and manipulate large
- amounts of data. In many ways the use of
- variables lies at the heart of this power. For
- example a simple arithmetic expression can be
- placed inside of a logical loop and within a
- couple of hours it could have done literally
- thousands upon thousands of calculations if it
- was given a constant supply of numbers to work
- from. But where can this data come from?
- We obviously need a way to store and read data
- that is less longwinded than the simple, hard-
- coded system we have employed so far of
- variablename = data or every business program
- would need thousands of lines that did nothing
- but assign values to variables (if you could
- think of enough names for them).
- We have already mentioned disk files and these
- will often be the most common way of storing
- large amounts of variable data on your Amiga.
- However, for storing reasonably small amounts
- of data that is to be constant over the life of
- your program the DATA, READ and RESTORE
- commands are useful.
- The keyword DATA is used to supply a list of
- several items of data, each separated from the
- next by commas. There can be many such DATA
- lines within each program. The keyword READ is
- used to look up this data, item by item, and
- assign it to a named variable, or several
- variables in turn (with the usual proviso that
- string data should not be assigned to a numeric
- variable etc.). When reading from the list
- MaxonBASIC starts at the very first DATA line
- it finds. When finished it remembers its exact
- position in the list, ready to begin again
- following the next READ command.
- The ´pointer´ that the computer uses to keep
- track of its position within the list can be
- moved with the use of the RESTORE command. If
- used on its own RESTORE resets this pointer to
- the front of the first DATA line, but RESTORE
- can also be used with a specified line number
- or line label to move the pointer more
- selectively.
- Text string data within the list does not have
- to be enclosed within quotes but you will get
- an error if you try to read such data into a
- numeric variable.
- Try this little program:
-
-
- DATA "A Box" ´ quotes because of space
- character
- DATA 100,50,100,150,200,150,200,50
- RESTORE
- READ a$
- LOCATE 4,18
- PRINT a$
- x0=200 : y0=50
- FOR a=1 to 4
- READ x1,y1
- LINE (x0, y0) - (x1, y1)
- x0=x1 : y0=y1
- NEXT a
-
-
- Another system for storing large amounts of
- information is the use of dimensioned
- variables. These allow information to be held
- in a much more dynamic way than is possible
- with DATA statements, but make the organisation
- and management of the data much easier than
- with simple variables.
- The keyword used to produce a dimensioned
- variable is DIM.
- A dimensioned variable allows several items of
- information to be accessed under just one
- variable name by specifying a numeric position
- for the data within a list. Take this example:
-
-
- DIM x(12)
-
-
- This dimensions the variable x to hold 13
- entries of data each accessed in turn as x(0),
- x(1), x(2), x(3), x(4), x(5), x(6), x(7), x(8),
- x(9), x(10), x(11) and x(12). This list of
- variables, all stored under the same name, is
- known as an .ib.array;. Data is placed in each
- of the entries of a dimensioned variable in
- just the same way as with a normal variable
- e.g.
-
-
- DIM A$(21)
- a$(12) = "Fred Smith"
-
-
- It is also possible to define a two dimensional
- array as in DIM x(9,9) which will store
- 10*10=100 items of integer data. The data in a
- two dimensional array can be accessed as if
- part of a table, with each data item read by
- specifying the ´row´ and ´column´ number.
- Similarly a three dimensioned array can be made
- which can be looked on as perhaps many
- different tables held on several pages of a
- book. Three dimensions is the limit to what we
- can visualise in terms of everyday objects but
- the number of dimensions you can have in an
- array is unlimited.
- Arrays of this form can be used to store data
- in a highly structured way. For example a
- series of string variables used by an address
- book program can be subdivided to store names,
- addresses, home telephone numbers, work
- address, work telephone number etc. and chosen
- parts of the data can be called up by
- specifying the appropriate array position.
- It is not always necessary to use the DIM
- command when using dimensioned variables. Any
- variable name that is given an array position
- when it is first used will automatically
- trigger the formation of a dimensioned array of
- that name as in:
-
-
- X(2)=20
- PRINT X(1)
-
-
- However when this system is used it creates a
- default array size of just 11 elements in each
- dimension referred to in the variable name.
-
- MaxonBASIC provides a range of error
- checks on arrays which are controlled via
- the compiler options requesters. With
- Array checks on you will be told at
- runtime if you access an array element
- beyond the dimensions of the array. When
- you are sure that your program is safe
- from such errors you may want to turn
- Array checks off to increase the speed of
- the program and decrease its size.
- However, be warned; if you are relying on
- the auto-dimensioning of small arrays
- described above, it is a good idea to turn
- Array check warnings on before you declare
- your code finished and turn checks off.
- This will tell you if you have
- accidentally used an array without
- dimensioning it first. If you run a
- program which uses an un-DIMed array with
- Array checks off, a program crash may
- result.
- The SHARED keyword can be used in conjunction
- with DIM to allow the array data to be shared
- between the main program and sub-programs
- without the need for a SHARED statement in each
- sub-program. Thus
-
-
- DIM SHARED A$(20)
-
-
- in the main program will allow the 21-element
- array A$ to be accessed by all sub-programs.
- Many people find the dimensioning system
- confusing in that an array of say x(10)
- actually stores eleven items of data. This is
- because it includes x(0) as a legal data
- position. The command OPTION BASE 1 forces the
- lowest entry in an array to be position 1, in
- which case DIM x(10) would only allow ten items
- to be stored. You can reset the default
- situation with the command OPTION BASE 0 but
- there are no other options allowed.
- REDIM is a command that allows the size of the
- dimensions of an array to be re-allocated. For
- example DIM x(9,19) can be REDIMensioned to the
- new layout of x(9,39) by:
-
-
- REDIM x(9,39) ´ all data in x() is lost
-
-
- Use this command with care as the data that is
- held in the array will be lost.
- REDIM PRESERVE allows one dimensional arrays to
- be enlarged or truncated whilst retaining the
- data in the un-altered array elements.
- When an array no longer is to be used it can be
- ERASEd, which clears all entries and reclaims
- the memory allocated.
- When writing sub-programs the situation often
- arises where the programmer can anticipate that
- the sub-program will be passed a variable array
- as a parameter, but cannot anticipate the
- likely size of this array. Similarly you may
- wish to write program routines that can work on
- an array that may constantly be REDIMensioned.
- MaxonBASIC has two functions which allow the
- size of a given array to be tested.
-
-
- UBOUND(name,x)
- returns the highest allowable entry of the
- ´xth´ dimension of the array allocated to the
- variable name.
-
-
- LBOUND(name,x)
- will do the same for the lowest allowable entry
- number, which will be either 0 or 1 depending
- on the setting of the OPTION BASE command
- before the array was first dimensioned.
- Finally there is a command that can be used
- with any pair of variables but is particularly
- useful for manipulating and moving around the
- data held in variable arrays.
-
-
- SWAP var1,var2
- will exchange the values held in the two
- variables, providing they are both numeric
- variables of the same type, or both string
- variables.
- Below is a complete example using these new
- array handling keywords:
-
-
- DEFINT a-z
-
- SUB Shell_Sort(Words$(1))
- STATIC HowFAR, Top, i, j
- Top=UBOUND(Words$)
- HowFar=Top\2
- DO WHILE HowFar>0
- FOR i=HowFar TO Top-1
- j=i-HowFar+1
- FOR j=(i-HowFar+1) TO 1 STEP -HowFar
- IF Words$(j)<=Words$(j+HowFar) THEN
-
- EXIT FOR
- END IF
- SWAP Words$(j), Words$(j+HowFar)
- NEXT j
- NEXT i
- HowFar=HowFar\2
- LOOP
- END SUB
-
-
- Type this shell sort program into MaxonBASIC
- and then devise a means of filling an array
- with some words and calling Shell_Sort to sort
- them into alphabetical order.
-
-
- Closing Down
-
- STOP, END and SYSTEM are all commands that
- produce the effect of stopping the current
- program, closing all files and returning
- control to the calling operating system. They
- can be used as options within an IFÉTHEN branch
- or similar for bringing an end to the program.
- If the current program that is being executed
- ever ´runs out of lines´ the effect is similar
- to placing an END command at the final line.
- SYSTEM differs from END and STOP in that it
- suppresses the Press any key message that
- normally appears when a MaxonBASIC program
- finishes.
-
-
- The Screen
-
- Producing output on the screen is at once one
- of the simplest and one of the most complex
- tasks possible. When you type PRINT "Hello"
- this single command triggers an enormously
- complex series of routines that produce exactly
- the correct pattern of dots on the screen, in
- exactly the correct place amongst the thousands
- of dots that there are, to create the image of
- the word Hello.
- Normally all of these processes are controlled
- automatically by the operating system of your
- computer. This makes things very much simpler
- for you, but also inevitably limits the options
- available for tailoring the display.
- On the other hand the Amiga has some of the
- most powerful and flexible graphics abilities
- yet seen on a microcomputer. To exploit these,
- MaxonBASIC allows a great deal of control over
- various aspects of the Amiga´s operating
- system, including Intuition. These are
- explained in the Chapter 9 : Operating system
- Support and the following section will only
- cover the commands briefly to put their usage
- into context.
-
-
- A Word About Intuition
-
- The Amiga range has an unusually sophisticated
- system of screen handling through the Intuition
- graphics environment. Intuition allows the user
- to control the screen display via multiple
- screens, multiple windows, graphic icons and
- many other display features and options. These
- can in turn be linked to, and controlled by,
- the keyboard and mouse input devices.
- Obviously, MaxonBASIC has to be able to let the
- user access the power of the operating system
- from within their own programs. However it
- would be completely impractical and unwieldy to
- provide special keywords for each of these
- functions, and their possible permutations.
- MaxonBASIC gives you a powerful and flexible
- interface with all the Amiga operating system
- calls by supplying a direct link via include
- files derived directly from the standard
- Commodore include files used by Assembler and C
- programmers.
- We will briefly describe the use of the include
- files here and give an extended example in the
- next section.
- Once the include file is installed and
- accessible to your own programs you will be
- able to call any of these procedures by name,
- as if they were keywords, and pass the required
- parameters to them to get the result you want.
- There are one or two pieces of bad news.
- Firstly, some of the operating system calls are
- detailed and fairly complicated and there is
- not sufficient room in this book to give
- details of what each one does.
- Operating System Support (Chapter 9) is a
- reference to all the various files provided,
- but if you intend to take Amiga programming
- more seriously, you will almost certainly have
- to buy copies of the Amiga ROM Kernel Manuals
- (even though these are targeted at C
- programmers), never-the-less they are the final
- word on using the Amiga operating system.
-
- Text on Screen
- When placing text on the screen, there are
- really two broad classes of commands - those
- that position the text on the screen, and those
- that place the text at that position, and
- control the way that it looks.
- The position where text will appear as soon as
- a PRINT or similar command is given is known as
- the text cursor. The screen of the computer is
- regarded as being divided into small squares,
- each big enough to hold one letter, of which
- there are eighty across and twenty down on a
- regular high resolution screen.
- The current horizontal position of this cursor
- can be determined by using the function POS,
- the vertical position by the function CSRLIN.
- The text cursor can be re-located at any of
- these text squares by the command LOCATE x,y
- where x is the vertical position and y the
- horizontal.
- Either x or y can be omitted if their current
- values are to remain unchanged (although the
- commas that separate them must remain if x is
- omitted). One other optional parameter makes
- the cursor invisible or visible - see the
- Command Reference. Try:
-
-
- LOCATE 10,10
- PRINT "Jim"
- LOCATE 9,10
- PRINT "Hello"
-
-
- Which will produce the output:
-
-
- Hello
- Jim
-
-
- Cursor positioning can also be achieved by
- typing the two ´invisible characters´ - spaces
- and tabs.
- The keyword SPC(x) can be inserted in any PRINT
- statement and it will cause the cursor to skip
- x spaces before the specified text is
- displayed.
- TAB(x) used in a similar situation will cause
- the text cursor to jump to column number x (if
- x is less than the current position, the cursor
- will move down by one screen line first). Note
- also the use of STRING$ and SPACE$ which can be
- used in PRINT statements.
-
-
- PRINT SPC(10), "Hello"
- PRINT TAB(10), "Hello"
-
-
- will both produce the result:
-
-
- Hello
-
-
- as will:
-
-
- Let A$=SPACE$(10)
- PRINT A$+"Hello"
-
-
- Note that the command TAB(x) does not really
- print a tab character but causes the cursor to
- jump to the required spot on the screen. The
- true tab character is designated by CHR$(9)
- which can be used by many printers, and some
- programs such as word processors, to trigger a
- jump to preset tab positions. This is the
- character usually returned by the tab key on
- the keyboard.
- With the cursor positioned where it is
- required, text can be displayed by the PRINT
- command. As we have seen even this has its own
- parameters that control the subsequent
- positioning of output - if text or a string is
- terminated by a semi-colon future output begins
- adjacent to that output. If it is terminated
- with a comma the next item to be printed starts
- at the next available x-column position on the
- screen. The default tab width is 14 and this
- can be changed using the WIDTH command.
- If text reaches the end of a line it
- automatically wraps around to the start of the
- next. However it is possible to define a
- smaller maximum line size by the use of the
- WIDTH command.
-
-
- WIDTH 20
- PRINT "Hello Hello Hello Hello Hello"
-
-
- will produce:
-
-
- Hello Hello Hello He
- llo Hello
-
-
- Normally when the PRINT command is asked to
- display data, such as a double precision
- number, it shows it on screen in a way that
- reflects its internal format. Often, however,
- it is not desirable to have too many decimal
- places displayed, or we may wish to manipulate
- the display in some other way e.g. to add
- currency symbols to the front of the data. The
- PRINT USING command does all this and more and
- is covered in detail in the Command Reference
- section.
- The WRITE keyword is also used to place data on
- the screen but it differs from PRINT in that it
- does not respond to any formatting commands.
- Try this example:
-
-
- REM An example of using WRITE
- a=42 : b=a MOD 5 : c#=22/7
- WRITE "The answer is "; a
- WRITE b*5, c#
-
-
- Run the program - is that what you expected?
- Any strings that are printed will be enclosed
- in quotes.
- In practice WRITE is more useful when
- debugging, or when producing disc files where
- the internal format of the number needs to be
- preserved. PRINT is of more value for the
- screen display in most other cases because of
- its extensive formatting control.
- Finally, an important command for controlling
- the text, and indeed graphics, display is CLS
- which means ´clear screen´. This command will
- also return the cursor to the top left hand
- edge of the screen ready for printing new data.
-
-
- CLI vs. Workbench - when is text not text
-
- The Amiga comes supplied with a standard
- character set which gives the only characters
- available for printing text in CLI mode.
- One of the main features of Workbench (and the
- whole of the graphical aspect of the Amiga
- operating system), on the other hand, is that
- it is possible to use several different fonts
- and text styles, such as italic or bold print,
- on screen. These special font styles cannot be
- handled in the same way as normal text - they
- are in effect ´pictures of text´ that are drawn
- on the screen. The ordinary MaxonBASIC commands
- for displaying and manipulating text are not be
- capable of manipulating them in the required
- way, and instead your program will have to pass
- commands through the OS interface header files.
-
-
- Graphics
-
-
-
- Two ways to produce graphics
-
- There is more than one way to produce a picture
- on your screen, but to appreciate the
- difference between the various techniques
- involves an understanding of how the screen
- display memory works.
- The image you see on the screen is made up of a
- matrix of small dots known as pixels - in the
- high resolution Amiga monochrome mode there are
- (at least) 640 * 200 pixels which makes 128000
- dots in total.
- As with any form of data, if the computer is to
- remember the image that is to be retained on
- the screen it needs to put aside a certain
- amount of memory for the task.
- It is possible for sections of the screen to be
- accessed directly, altered, moved, copied or
- saved to disk.
- Say that we have a screen with a simple graphic
- image on it - one straight line. The program
- that draws that line may be only one command
- long and can be saved in a disk file that is
- less than 1K in size. Every time we wish to
- create that graphic image again the program can
- almost instantly be run.
- However if we wish to save the entire memory
- image of that screen the file created will be
- many times as large, and will probably still be
- loading long after the first version has
- finished.
- Alternatively a detailed graphics image, say a
- landscape scene, may require an complex program
- of many hundreds of lines to re-create it. If
- the screen picture is a digitised image of a
- video picture or a creation from a computer art
- package it may be practically impossible to
- write a program that could reproduce it.
- In this case a simple file that stores the
- pixel data for the screen image will be the
- most memory efficient and speedy system to use.
- MaxonBASIC´s graphics keywords contain options
- that will make it easy for you to choose
- whichever of the above approaches best suit
- your needs, or to mix them at will.
- As with text the following keywords require a
- means of signalling to the computer exactly
- where you want the graphics to appear as well
- as what graphic image it is to print. The
- current position where graphics will appear is
- known as the graphics cursor.
- The following commands all produce certain
- simple shapes on the screen at specified
- positions. Their full range of permutations and
- options are detailed in the Command Reference
- chapter.
- Movements of the graphics cursor can be
- expressed in absolute coordinate terms like
- that used to move the text cursor (although of
- course the range of coordinates available
- changes depending on the current screen
- resolution). Alternatively it is sometimes
- possible to express the required movement
- relative to the current graphics cursor
- position using STEP.
- LINE is used to draw a line or a box on the
- screen in a chosen line style and colour.
- CIRCLE does the same for any size of arc,
- circle or ellipse.
-
- LINE (100, 100) - (200, 100)
- will draw a line from the pixel position
- (100,100) to the pixel position (200,100).
- LINE and PAINT are used to draw shapes that are
- filled by a specified colour or tile pattern.
- The ability to rapidly and automatically fill
- shapes with a given pattern, which can be
- extremely complex, is one of the most powerful
- features of the Amiga and can give a very
- professional look to your programs if used with
- restraint.;
- PSET and PRESET both draw a pixel dot at the
- specified position on the screen in the
- specified colour. If the colour option is
- omitted PSET will default to the current
- foreground colour but PRESET will default to
- the background colour. POINT is a complementary
- command that will read the colour displayed at
- specific pixel position.
-
-
- Using Colours
-
- The standard Amiga A500 computer is capable of
- displaying a maximum of thirty-two colours at
- once (without using EHB or HAM modes). The
- current colours for printing and drawing can be
- selected by the programmer from a list of 0-31,
- detailed in the Command Reference section,
- under COLOR.
- The extra palette and colours of the Amiga 1200
- and 4000 can be accessed from MaxonBASIC in two
- ways: via the built-in PALETTE statement and
- via the Graphics library LoadRGB32 and SetRGB32
- functions.
- COLOR (with apologies for the American
- spelling) can be used to choose the colour with
- which text is printed and the colour of the
- background, or ´paper´, on which it is
- displayed. When programming in CLI mode these
- are the only options available.
- PALETTE ;allows the programmer to change the
- actual colours displayed on the screen. In this
- way the displayed colours can be changed even
- when, say, in the standard Workbench mode which
- uses a screen display with only 4 colours (0 -
- 3).
- Try the following program:
-
-
- REM $NOWINDOW ´inhibit the standard BASIC
- window
- DEFINT a-z
-
- REM $INCLUDE Graphics.bh ´Use Graphics for
- WaitTOF
- LIBRARY OPEN Ògraphics.libraryÓ
-
- ´ Open a screen for our window
- SCREEN 1,,,2,2 ´4 color high-res non-
- interlaced screen
- WINDOW 1,,,511,1 ´a "Works-Burger" window
- (everything on it!)
-
- ´ Draw three boxes in a triangular formation
- FOR i = 1 TO 3
- x = 270 ´ set up co-ordinates for each box
- y = 25 ´ depends on the screen resolution!
- IF i = 2 THEN x = x - 75 : y = y + 65
- IF i = 3 THEN x = x + 75 : y = y + 65
- LINE (x, y) - STEP (100, 50), i, BF
- NEXT i
-
- ´ Cycle through all the colours
-
- FOR red! = 0.0 TO 1.0 STEP 0.03125
- FOR green! = 0.0 TO 1.0 STEP 0.03125
- FOR blue! = 0.0 TO 1.0 STEP 0.03125
- ´ initialise each of the three colours
- we use
- PALETTE 1, red!, green!, blue!
- PALETTE 2, blue!, red!, green!
- PALETTE 3, green!, blue!, red!
- WaitTOF
- WaitTOF
- NEXT blue!
- NEXT green!
- NEXT red!
-
-
- A colour that is altered by the PALETTE command
- changes instantly on the display without
- anything having to be redrawn. Many forms of
- graphics effects and computer animation are
- possible as a result.
- For instance two different colour numbers can
- be set by the PALETTE command to actually
- display the same result on the screen. An image
- drawn in one colour will therefore be invisible
- against a background using the other. A new
- PALETTE command that sets the image colour
- number to a different setting will make that
- image appear instantaneously.
-
- REM $INCLUDE Graphics.bh
-
- This compiler meta-command includes all
- the definitions, functions and sub-
- programs available in the standard Amiga
- graphics library. We do this to gain
- access to the WaitTOF sub-program which
- waits for the Amiga to indicate that the
- video-beam on the monitor has returned to
- the top of the display. This allows us to
- animate the colours on the display without
- them flickering (caused by changing the
- colour whilst the beam was passing the
- point at which we changed it).
-
-
- Pre-tokenised files
-
-
-
- The next program we consider is going to use
- the Amiga´s graphics library without using the
- BASIC commands. It needs to include both the
- Exec.bh and Graphics.bh files. When you are
- developing such a program its a bit boring
- waiting for the compiler to tokenise all the
- constants in the include files every time you
- make a change to your program; after all ,
- these identifiers are going to be the same each
- time. MaxonBASIC 3 enables you to pre-tokenise
- these and then load the pre-tokenised
- information when you compile your main program.
- For the technical details of pre-tokenisation
- see the end of the Compiler Section but here´s
- how to use it in practice:
- First create a file with just the includes that
- we want like this
-
-
- REM $INCLUDE Exec.bh
- REM $INCLUDE Graphics.bh
-
-
-
- and save this out as abc_inc.bas using the Save
- command from the Project menu. Select Tokenise
- from the Program menu and the pre-tokenised
- file abc_inc.t will be produced. To use this
- file select File sub-item from the Compiler
- item on the Settings menu.
-
-
- Now click on Set by Tokens file and select the
- abc_inc.t file with the file requester.
- Now if you compile a program that uses these
- include files, it will compile much more
- quickly. Note that you will need to remove, or
- comment out, the corresponding REM $INCLUDE
- lines in your main program otherwise you´ll get
- two copies!
- When you have finished using a pre-tokenised
- file you can select another one or select the
- Token File line and use AX to remove an
- existing one.
-
-
- Example Graphics Library Program
-
-
- Here´s a program that uses the Amiga´s graphics
- library without using the BASIC commands. This
- program should help you to understand the
- principles of using the Amiga libraries.
-
-
- DEFINT a-z
-
- ´REM $INCLUDE Exec.bh
- ´REM $INCLUDE Graphics.bh
-
- LIBRARY OPEN "graphics.library"
-
- CONST length% = 40, skew% = 15
- CONST start% = 260, ystart% = 110
- fb$ = "MaxonBASIC 3"
-
- ´
- ´SafeSetOutlinePen
- `a backwards (<V39 graphics) compatible
- SetOutlinePen
- ´
- SUB SafeSetOutlinePen(BYVAL w&, BYVAL c)
- STATIC junk&
-
- IF PEEKW(LIBRARY("graphics.library") +
- lib_Version) >= 39 THEN
- junk& = SetOutlinePen&(w&, c)
- ELSE
- POKEB w& + AOlPen, c
- POKEW w& + RastPortFlags, PEEKW(w& +
- RastPortFlags) OR AREAOUTLINE&
- END IF
- END SUB
-
- REM Sub-program to draw a 3-D box with a letter
- SUB draw_box(BYVAL rp&, BYVAL x, BYVAL y, ch$)
- STATIC ch_x, ch_y, junk&
-
- REM Draw outline of a box
- SetAPen rp&, 0 ´ set foreground pen to
- background color
- junk& = AreaMove(rp&, x, y)
- junk& = AreaDraw(rp&, x + skew, y - skew)
- junk& = AreaDraw(rp&, x + length + skew, y -
- skew)
- junk& = AreaDraw(rp&, x + length + skew, y +
- length - skew)
- junk& = AreaDraw(rp&, x + length, y + length)
-
- junk& = AreaDraw(rp&, x, y + length)
- junk& = AreaEnd(rp&)
-
- REM Now draw 3 lines to complete 3-D box
- SetAPen rp&, 1 ´ select standard pen
- Move rp&, x, y
- Draw rp&, x + length, y
- Draw rp&, x + length + skew, y - skew
-
- Move rp&, x + length, y + length
- Draw rp&, x + length, y
-
- REM Draw the letter text, centred in the box
- ch_x = TextLength&(rp&, SADD(ch$), LEN(ch$))
- ch_y = PEEKW(rp& + TxHeight)
- Move rp&, x + (length - ch_x) / 2, y + (length
- + ch_y) / 2
- Text rp&, SADD(ch$), LEN(ch$)
- END SUB
-
- REM The main program
-
- ´force the BASIC runtime library to initialise
- TmpRas and
- ´AreaInfo in the default window´s RastPort (!)
- AREAFILL
-
- SafeSetOutlinePen WINDOW(8), 1 ´set the outline
- pen colour
-
- draw_box WINDOW(8), xstart, ystart, "B"
- draw_box WINDOW(8), xstart + 7 * length / 6,
- ystart, "C"
- draw_box WINDOW(8), xstart + 7 * length / 12,
- ystart - 7 * length / 6, "A"
-
- fb_width = TextLength&(WINDOW(8), SADD(fb$),
- LEN(fb$))
- fb_height = PEEKW(WINDOW(8) + TxHeight)
- fb_x = xstart + (13 * length \ 6 + skew -
- fb_width) \ 2
- fb_y = ystart + length + fb_height * 3 \ 2
-
- REM Display picture title
- Move WINDOW(8), fb_x, fb_y
- Text WINDOW(8), SADD(fb$), LEN(fb$)
-
- END
-
-
- Now let´s see how it´s done É
- First of all, what are we trying to draw?
- Answer: three 3-dimensional boxes, with letters
- inside them and a title below all this. How are
- we going to do the boxes?
-
- We have to draw 3 boxes, all the same (except
- for the letter inside it), so it makes sense to
- have a sub-program to draw one box. To make a
- box, we could just draw 9 lines but there are
- several graphics library call to help us out É
- The graphics library functions AreaMove,
- AreaDraw and AreaEnd are used to define the
- vertices of the polygon we want to fill. Look
- at the box in Figure 3.1, formed by points 1,
- 2, 3, 4, 5, and 6 - this is a closed polygon
- and we could therefore draw it with AreaDraw.
- What are the points? Well, if point 1 is (x,y)
- and the length of each side of the box is
- length and the depth, measured vertically and
- horizontally, is skew then the points are as
- follows:
-
- Point 1 :(x, y)
- Point 2 :(x+skew, y-skew)
- Point 3 :(x+length+skew, y-skew)
- Point 4 :(x+length+skew, y+length-skew)
- Point 5 :(x+length, y+length)
- Point 6 :(x, y+length)
-
- So, to draw this polygon we must set up the 6
- points (we AreaMove to the first point,
- AreaDraw to the next five, then mark that we´re
- done with AreaEnd):
-
-
- REM Draw outline of a box
- junk& = AreaMove(rp&, x, y)
- junk& = AreaDraw(rp&, x + skew, y - skew)
- junk& = AreaDraw(rp&, x + length + skew, y -
- skew)
- junk& = AreaDraw(rp&, x + length + skew, y +
- length - skew)
- junk& = AreaDraw(rp&, x + length, y + length)
- junk& = AreaDraw(rp&, x, y + length)
- junk& = AreaEnd(rp&)
-
-
- To draw this polygon we should first set up the
- colour index of the fill and the border; this
- is done with SetAPen (for the fill) and the
- curious SafeSetOutlinePen sub program (which
- sets the outline colour, which we´ll
- investigate later, but ignore for the momentÉ).
- SetAPen simply sets the Amiga´s foreground pen
- (which is historically known as the A-Pen.
-
- The Amiga has a second pen, the background
- pen, which is known as the B-Pen - not
- surprisingly the sub-program SetBPen is
- used to set it! Historically the outline
- pen is also known as the O-Pen.
- In order to call the SetAPen sub-program we
- also need a ´RastPort pointer´; the internal
- details of this aren´t important to us at the
- moment, but a quick look in the Command
- Reference tells us that the WINDOW(8) function
- gives us a pointer to the RastPort for the
- current window.
-
- Internally the Amiga graphics library is
- capable of drawing into many windows at
- the same time (since the Amiga is a
- multitasking machine), so for each of
- these drawing operations it needs a
- drawing context; the RastPort is this
- context information (it contains the
- current A pen and B pen settings for
- example). A RastPort is associated with
- every window in the system, every screen,
- and any other RastPorts which the
- programmer creates.
- Now, drawing the polygon hasn´t given us our 3D
- box yet - we need to add lines from point 7 to
- point 1, from point 7 to point 3 and from point
- 7 to point 5 (see Figure 3.1). We need another
- graphics library call to do this (we could use
- the BASIC LINE command but since we´re trying
- to do this without using the BASIC routinesÉ
- the two calls which we need are Move (to move
- the drawing position), and Draw (draw a line
- from the current drawing position).
-
-
- REM Now draw 3 lines to complete 3-D box
- SetAPen rp&, 1 ´ select standard pen
- Move rp&, x, y
- Draw rp&, x + length, y
- Draw rp&, x + length + skew, y - skew
-
- Move rp&, x + length, y + length
- Draw rp&, x + length, y
-
-
- Again we need to select the correct pen for
- drawing, so SetAPen is again used to select the
- pen we need (pen 1 this time).
-
- The pen numbers used on the Amiga from
- Workbench 2.0 onwards are not strictly
- fixed (as we are using them), the correct
- procedure is to call the OS routine
- GetScreenDrawInfo which returns a complete
- description of the user´s preferred
- graphic context (as set by the various
- Preferences editors), and then extract the
- desired information; for simplicity this
- has been skipped here.
- So, we´ve drawn a 3D box; now we have to put a
- character in it. To do this we use the graphics
- library Text sub-program; this draws a
- character at the current graphic location (as
- set by Move).
- We also need a bit of arithmetic to work out
- where to place this character so that it
- appears in the middle of our box. First we need
- to know the width and height of a character -
- can the graphics library help? There´s a
- routine called TextLength that returns the
- number of pixels needed to enclose a text
- string horizontally:
-
-
- ch_x = TextLength&(rp&, SADD(ch$), LEN(ch$))
-
-
- The TextLength function takes three parameters:
- rp& - the now familiar RastPort pointer, a
- pointer to the start of the string ch$ (for
- which we use the SADD function, this converts a
- BASIC string into a pointer suitable for the
- operating system), and LEN(ch$) - the length of
- the string.
- Having found the number of pixels across our
- text will be, we now need to find its height;
- this is stored in the RastPort pointed to by
- rp&. To find the value, we have to PEEK at the
- word in the RastPort structure at the TxHeight
- offset, hence:
-
-
- ch_y = PEEKW(rp& + TxHeight)
-
-
- So now we have ch_y as the height of the string
- and ch_x as the width. To put the string in the
- centre of the front face of the box (the face
- is length wide by length high, remember), we
- need to put the bottom left of the character at
- co-ordinate (x+length/2-ch_x/2,
- y+length/2+ch_y/2) where (x,y) is the top left
- of the front face. Look at Figure 3.1 to see
- that this is right. Keep looking!
- So, this should do it:
-
-
- Move rp&, x + (length - ch_x)/2, y + (length +
- ch_y)/2
-
-
- Then having moved to the correct co-ordinates
- we actually have to draw the text:
-
-
- Text rp&, SADD(ch$), LEN(ch$)
-
-
- Notice that the parameters passed to the Text
- sub-program are identical to those passed to
- TextLength.
- That effectively completes the draw_box sub-
- program. Notice that we have passed the
- RastPort (rp&), the top left (x, y) co-
- ordinates as parameters and also the letter
- that is to be contained in the box is a
- parameter (the third one).
- Now we´ve completed the draw_box sub-program we
- need to write our main program, obviously the
- main thing for this to do is to draw the three
- boxes and the title, however first we need to
- do some extremely important setup:
-
- ´force the BASIC runtime library to initialise
- TmpRas and
- ´AreaInfo in the default window´s RastPort (!)
- AREAFILL
- The AREAFILL command is a standard BASIC
- command which is normally used for doing very
- much the same sort of thing as we did with
- AreaMove et al. However when used in this
- special way (with no parameters) on the default
- window it forces several internal things to be
- set up in the RastPort which are not normally
- set up until a fill occurs (to save memory).
- Since we´re not using the BASIC fill commands
- we must ask BASIC to set up these things in
- advance for us.
-
- The elements within the RastPort which
- must be set are the TmpRas (a second,
- temporary, RastPort) and an AreaInfo
- array. The first of these is used whilst
- the graphics library is rendering the
- resulting polygon, the latter is used for
- storing the vertices of the polygon until
- the AreaEnd sub-program is called (BASIC
- normally initialises the AreaInfo with
- enough space for 20 vertices - if you
- exceed this any additional vertices will
- be ignored).
- The other piece of set up which we ignored
- until now was setting up the colour of the
- outline used for the polygons. To do this we
- need a bit of chicanery involving the RastPort,
- together with some graphics library version
- dependent code:
-
-
- SUB SafeSetOutlinePen(BYVAL w&, BYVAL c)
- STATIC junk&
-
- IF PEEKW(LIBRARY("graphics.library") +
- lib_Version) _
-
- >= 39 THEN
- junk& = SetOutlinePen&(w&, c)
- ELSE
- POKEB w& + AOlPen, c
- POKEW w& + RastPortFlags, _
- PEEKW(w& + RastPortFlags) OR
- AREAOUTLINE&
- END IF
- END SUB
- É
- SafeSetOutlinePen WINDOW(8), 1 ´set the outline
- pen color
-
-
- The first line checks the version of the
- graphics library which is in use, the function
- LIBRARY("graphics.library") finds the location
- of the library base pointer, to this we add the
- offset to the version number word (lib_Version)
- and PEEK the word at the location. In this case
- we need a graphics library version after V39
- (Workbench 3); in this version an additional
- function, SetOutlinePen was added which sets
- the outline pen for us.
-
-
- IF
- PEEKW(LIBRARY("graphics.library")+lib_Version)>
- =39 THEN
-
-
- If we find we don´t have a new enough graphics
- library, then we fall back to setting the
- outline pen in a manner which works on older
- versions of the operating system:
-
-
- POKEB w& + AOlPen, c
- POKEW w& + RastPortFlags, _
- PEEKW(w& + RastPortFlags) OR AREAOUTLINE&
-
-
- Here we first set the outline pen by POKEing
- the byte at the AOlPen (Area Outline Pen)
- offset in the RastPort (w&), then we need to
- tell the graphics library that it should render
- the pen when drawing the areas (as opposed to
- not drawing an outline around the polygon at
- all). To do this we have to set the AREAOUTLINE
- flag in the RastPort´s Flags; first we PEEK the
- existing value (since we don´t want to disturb
- any of the current bits which are set), OR in
- the value of the AREAOUTLINE flag, then POKE
- the result back.
- Finally we call the SafeSetOutlinePen sub-
- program in the main body of our program to set
- the pen, as you can see the sub-program nicely
- hides all of the complexity of setting the
- outline pen correctly on all OS versions,
- making for a clearer, easier-to-understand
- program.
- Now that we´ve (finally!) completed all our
- setup, all that remains is to call draw_box 3
- times (for 3 boxes) and then to write some text
- underneath the whole thing. Again, we´ll use
- Text to write the message and do a little
- arithmetic to make sure that the text message
- is centred under the boxes:
-
-
- draw_box WINDOW(8), xstart, ystart, "B"
-
- draw_box WINDOW(8), xstart + 7 * length / 6,
- ystart, "C"
- draw_box WINDOW(8), xstart + 7 * length / 12,
- ystart - 7 * length / 6, "A"
-
- fb_width = TextLength&(WINDOW(8), SADD(fb$),
- LEN(fb$))
- fb_height = PEEKW(WINDOW(8) + TxHeight)
- fb_x = xstart + (13 * length \ 6 + skew -
- fb_width) \ 2
- fb_y = ystart + length + fb_height * 3 \ 2
-
-
- We hope that has given you some insight into
- using the Amiga libraries - it is really not as
- daunting as it first looks and well worth the
- initial effort!
- Of course, if you find the library functions
- and sub-programs difficult to remember or
- clumsy to use you can always re-write and re-
- name them.
-
- When using the Amiga´s operating system
- directly it is essential to have
- documentation on the various calls; this
- is all contained in the ROM Kernel Manuals
- (RKMs). Although these are written for C
- and Assembler programmers, learning a
- little C is enough understand much of what
- the RKMs cover. Without the RKMs
- programming the Amiga at the operating
- system level is almost impossible.
-
-
- Blitting
-
- There is an alternative approach to producing
- graphics effects which relies on using keywords
- which directly access and manipulate areas of
- the screen display memory. Moving or copying
- such areas of memory, or switching one area of
- screen memory with another, can be used to
- produce outstanding animation effects. Moving
- bits of screen memory around is known as
- blitting (the word stems from bit block
- transfer).
- GET and PUT allow the program to pick up a
- specified rectangular block from the screen
- display and place it in a different position on
- the screen. An array of the appropriate size
- has to be specified for storing the data. A
- block that is picked up by GET is not
- automatically obliterated from the screen but
- merely copied into an array.
- Several arrays can be filled using the GET
- command. These can also be copied to a
- sequential disk file in the same way that any
- array would be, ready for subsequent re-
- loading. In this way you could prepare a
- program that contained several digitised
- images, for example, that can be used for
- illustrations, or could be subsequently PUT
- into the same position to produce an animated
- effect.
- In the past these techniques have been felt to
- consume too much memory to allow their frequent
- use in micro-computer programs, but most Amiga
- machines have lots of RAM to spare and can hold
- many such arrays at once, leaving you free to
- produce incredibly sophisticated effects with
- ease.
- The PUT command has several options that allow
- different graphics and animation effects to be
- achieved using the techniques described in
- Using Logical Operators in Arithmetic where an
- example of GET and PUT was also given. These
- options are detailed in the Command Reference
- section. Trial and error is also a good way of
- seeing how these routines work in practice -
- experiment with PUTting picture blocks onto a
- blank screen and onto a screen that already
- contains a detailed image to see how different
- effects can be achieved (people using a colour
- display will find a lot more interesting
- effects are possible than with a monochrome
- monitor).
-
-
- Windows
-
- Anyone who has had experience of using the
- Amiga will quickly learn what windows are, what
- they can do and how they can give your programs
- a professional and polished air. Many languages
- will only allow you to use windows by making
- rather complicated calls to the Intuition
- system.
- MaxonBASIC however comes with a comprehensive
- selection of built-in commands that are
- designed to make the process of calling windows
- as easy and as fluent as possible. The built-in
- commands are fully documented under the WINDOW
- keyword, in the Command Reference section and
- we will give an example here.
- WINDOW is a remarkably compact keyword
- requiring you only to provide several
- parameters such as the size, position, nature
- and contents of the window and MaxonBASIC and
- Intuition do all of the work of drawing the
- image on screen etc.
- Note that when using multiple windows each is
- referred to by a specific identification number
- in a way that parallels those required for
- managing several disk files at once.
-
-
- DEFINT A-Z
-
- ´ get the width & height of the free BASIC
- window
- ww = WINDOW(2)
- wh = WINDOW(3)
-
- ´ draw an ellipse using pen 1 in the free BASIC
- window
- CIRCLE (ww \ 2, wh \ 5), ww \ 3, 1,,, (wh / ww
- / 2)
-
- ´ fill from the centre using pen 3, outwards to
- pen 1
- PAINT (ww \ 2, wh \ 5), 3, 1
-
- ´ open another window, id number 2
- WINDOW 2, "Another window", (ww \ 4, wh \ 2) -
- (ww * 3 \ 4, wh)
-
- ´Print something novel in window 2
- PRINT "Welcome to MaxonBASIC 3!"
-
-
-
-
- Talking to the Outside World
-
- It is probably true to say that taking in input
- and producing output, are the most important
- jobs that a computer program has to do.
- There is very little value to line after line
- of complex calculation or data manipulation
- unless at the end of it all an answer is
- displayed on a page or the screen. We have
- already seen that without a PRINT command most
- programs are functionally useless.
- Similarly it is certainly true that, with the
- exception of some graphics demos and the likes,
- most programs are useless unless they take some
- information from the user, a keypress or menu
- choice at the very least, or from the outside
- world via equipment such as a temperature
- sensor.
- We have already looked at what are perhaps the
- two most fundamental commands that deal with
- input and output of information, INPUT and
- PRINT. There are however many different options
- that exist to complement or modify these basic
- keywords.
-
-
- Input and Output
-
- There are several possible sources of
- information, not just data but also commands
- from the user, that are available for your
- program to act upon - these include the
- keyboard and mouse, files held on disk, and the
- computer´s hardware ports. The options
- available for output include again the hardware
- ports, disk files, the speaker, a printer and,
- of course, the screen.
- The operating system of the Amiga computer
- itself can also often be looked upon as an
- external source of information for your
- programs as it acts as an intermediate between
- BASIC and the hardware.
- The operating system is a special master
- program that is in charge of everything the
- computer does. It recognises what key you are
- pressing on your keyboard, it knows how to make
- the disk drives spin round when required and so
- on. It is this master program that also
- contains all of the graphics routines.
- The operating system keeps charge of the date
- and time clock that is available through
- commands such as DATE$, it is the operating
- system that provides information on the status
- of the disk drive (such as which files are
- present), it is the operating system that
- detects when many hardware devices signal an
- error (such as disk missing from the drive).
- All of these items of information can be used
- by your own programs to control which command
- lines and subroutines are to be executed.
- Similarly when outputting data or instructions,
- the operating system may be the immediate
- receiver of the information you send. For
- instance when sending graphics commands your
- programs will be talking to the graphics
- library to get the desired effects rather than
- attempting to manipulate the screen display
- directly.
- Each of these input/output ´targets´ can be
- accessed by special related keywords or pre-
- defined library routines.
-
-
- The Keyboard, Joystick and Mouse
-
- We have already looked at how the INPUT command
- works but although this is really a very simple
- keyword there are a few important options
- available.
- You have the ability to suppress the question
- mark the command displays by the use of a comma
- instead of a semi-colon after the keyword.
- The response given by the user must of course
- match the type of variable expected by the
- INPUT keyword or the user will get the message
- Redo from start. This is a wonderfully
- ambiguous message and means ´redo the current
- entry from the start´ (as if you could do
- anything else) rather than ´redo every input
- question you may have just been asked´. Strings
- entered as input need not be placed within
- quotes, and as long as they are not so enclosed
- the quote character - " - can be used as part
- of the string (but obviously not in the first
- character position).
- Several items of data can be requested and
- entered in one go, although the number and type
- of the data entries must again match those
- required. In both the program line and during
- the entry process all items must be separated
- by commas.
- LINE INPUT will read an entire line of data,
- until terminated by a carriage return, and
- assigns it to one string variable. It does this
- even when the information is separated into
- sections by commas which would have been taken
- to be data separators by the INPUT command.
- If you have a line:
-
-
- INPUT A$, B$, C$
-
-
- and the user enters:
-
-
- Bob Smith, 10 New Road, London
-
-
- then A$ will equal Bob Smith
- Whereas if you had a line:
-
-
- LINE INPUT A$
-
-
- which is given the same input A$ would be given
- the value of:
-
-
- Bob Smith, 10 New Road, London
-
-
- LINE INPUT is particularly useful when reading
- an ASCII file from disk, e.g. a file created by
- the MaxonBASIC editor. Each line can be
- extracted from the file in turn and displayed,
- printed, or both regardless of whether it
- contains commas or any other form of
- punctuation.
- Both INPUT and LINE INPUT allow the user to
- edit the data while it is being entered to make
- corrections by using the Backspace key to
- delete data already entered.
- A closely related command is INKEY$ which reads
- the keyboard to see if any key, or combination
- of keys, has been pressed. If no key has been
- pressed an empty or null string is returned.
- The important differences from INPUT are that
- only one character value is returned at a time,
- and that the program does not have to wait for
- the user to hit Return before it can start to
- respond to the key.
- If a key is pressed which is defined to produce
- a string of text, such as one of the function
- keys, INKEY$ will only take one character from
- the string every time the command is made.
- INKEY$ is often used in conjunction with
- logical loops such as DOÉLOOP to wait for a
- response from the user e.g.
-
-
- SUB Wait
- PRINT "Press any key to continue"
- DO
- LOOP UNTIL INKEY$<>""
- END SUB
-
-
-
- Note that this is an example of
- particularly bad Amiga programming!
- Because of the way we´ve used INKEY$ the
- computer is being forced to Òbusy waitÓ,
- i.e. we´re keeping it tied up doing
- nothing which means that other programs
- can´t have as much time to execute. A much
- better method is to use the SLEEP
- statement which puts your program to sleep
- until an event of some form arrives.
- The INPUT$(x) command is like a hybrid between
- INPUT and INKEY$ - it reads x number of
- keypresses from the keyboard and passes them
- directly to the program. This command is
- particularly useful as it allows a long string
- to be entered from the keyboard which need not
- be terminated by Return, and which can even
- contain, CHR$(13), in the middle somewhere.
- Control of the mouse is via the keyword MOUSE
- This is very simple to use and there is a good
- example of its use in the Command Reference
- section.
- The various joystick ports can be read by the
- following keywords.
-
-
- STICK(n)
- is a function that returns a reading of the
- position of a joystick. The information the
- program requires from this function is
- signalled by the value of n which is passed.
- This can be 0 - 3 and the values returned
- respectively are the x position of joystick 1,
- the y position of joystick 1, the x position of
- joystick 2 and the y position of joystick 2.
- The values returned are -1 (Left/Up), 0
- (Centre) and 1 (Right/Down).
-
-
- STRIG(n)
- returns a value as to whether any of the
- joystick buttons has been pressed; n can be
- from 0 to 3. Respectively these signal whether
- the button on joystick 1 has been pressed since
- the last STRIG(0) command, whether button is
- currently pressed, whether button on joystick 2
- has been pressed since the last STRIG(2)
- command, whether button is currently pressed.
-
-
- The Printer
-
- The printer is not a standard peripheral for
- the Amiga computer, but it is so common for
- people to buy one that it is given full support
- from the operating system and from within
- MaxonBASIC.
- The commands used for producing output on the
- printer are in many ways identical to those for
- laying out text on the screen, with the obvious
- exceptions that it is usually only possible to
- move the printhead down the page (some printers
- have a limited reverse paper feed option but it
- is rarely effective over more than a line or
- two) and that text can be overprinted, but not
- erased.
- The LOCATE command is therefore of no use, and
- steps down the page are usually accomplished by
- sending a series of carriage returns, by
- sending special codes that force a printer
- ´line feed´ (most machines allow you to set the
- line feed to be of variable height) or that
- cause the printer to perform a ´vertical tab´
- jump. If your printer supports either of the
- latter two options they will be explained more
- fully in the accompanying documentation
- Some printers, especially those that are
- capable of different print pitches, can also
- use very many more characters across the page
- than is possible on the screen.
- The LPOS keyword returns the value for what the
- computer feels should be the horizontal
- position of the print head on the paper, based
- on how many characters have been sent to the
- printer since the last carriage return. The
- situation can actually arise where the computer
- gets this wrong, e.g. if the printer head was
- left in an unusual position by a previous
- program. The keyword is also unable to keep
- track of what effect, if any, the tab character
- is producing on the printer (the size of tab
- jumps can be defined on most machines) but on
- the whole the information returned should be
- reliable.
- LPOS is typically used for testing whether
- there is enough room on the line remaining to
- send the next word you wish to print. If there
- is not, a carriage return/line feed can be sent
- first ensuring that no words are broken in
- half.
- Because of the relative lack of control you
- have over this feature there is no keyword for
- returning the vertical position of the print
- head.
- As with text printing on screen the WIDTH
- LPRINT command can be used to set the maximum
- width of the printed display. After the
- specified number of characters have been sent a
- new line is automatically started.
-
-
- Sound
-
- MaxonBASIC provides many ways of handling sound
- on your Amiga computer. First of all, here is
- some (very) simple keywords.
- We have met BEEP already and there is really
- nothing more to say about it as it is a very
- simple command. It is most useful as a means of
- signalling an error or attracting attention to
- a message in your program. It is worth noting
- that a similar effect can be achieved by the
- command:
-
- PRINT CHR$(7)
-
- This can be useful when you have written a
- routine that reads a series of ASCII numbers,
- say from a file held on disk, and prints them
- onto the screen. ASCII number 7 can be held
- within the file to signal the end of a
- particular message or something like that.
- Although we´ve listed BEEP as a sound command
- on the Amiga as standard it is mute! Never-the-
- less it is usually thought of as a sound
- command.
- The command SOUND is only slightly more
- sophisticated. It allows the pitch and duration
- of the note to be varied, and is detailed in
- the Command Reference chapter.
- The WAVE command is a useful complement to the
- keyword SOUND as it allows the type of noise
- that is to be produced to be controlled by
- defining the waveform and envelope of the
- noise. This is again explained in more detail
- in the Command Reference section.
-
-
- The Timer
-
- The timer is not a true physical device on the
- Amiga computer, but the effect of one is
- simulated by the operating system as a
- constantly active background task. As long as
- the machine is not turned off or reset the
- current date and time can be read or reset
- through MaxonBASIC.
-
- DATE$ and TIME$ are used as functions to return
- the current value of the ´clock´ settings; the
- values are returned as specially formatted
- strings.
-
- TIMER is a function that returns the number of
- seconds since midnight. The returned value is a
- single-precision numeric value so two calls to
- the TIMER function can be used to time a given
- part of the program with much more accuracy
- than using the TIME$ command (TIME$ returns
- information as a specially formatted string).
- TIMER´s accuracy is to the 50th of a second,
- whereas TIME$´s accuracy is 1 second.
- If you have a program that wants to do
- something regularly, may be to update a status
- display you can use the ONÉTIMER statement.
- Here´s a rather silly example:
-
-
- ON TIMER(2) GOTO timer_handler
- TIMER ON
-
- FOR i=1 TO 1000
- PRINT i
- NEXT i
-
- STOP
-
- timer_handler:
- PRINT "hello"
- RETURN
-
-
- Here every 2 seconds (the number in brackets in
- the ONÉTIMER statement, the timer_handler
- routine will be executed. The TIMER ON
- statement starts the timer off; if you want to
- stop a timer for a while (perhaps because you
- need to do something urgently like download a
- file) you can do this with the TIMER OFF
- command; use TIMER ON to switch it back on
- again.
- i.file handling;
-
-
- Managing Files
-
- MaxonBASIC provides a complete suite of
- commands to allow the programmer to access and
- control the filing system. All large utility
- programs you write should employ these commands
- to allow the user to best organise the layout
- of files on the disk from within your program,
- particularly if they may need to create room
- for data by erasing or copying some of the
- existing titles.
- FILES will produce a list of all files present
- in the current default drive and sub-directory.
- Try:
-
-
- FILES
-
-
- you should get a list of all files on disk.
- Now try:
-
-
- FILES "DF0:"
-
-
- you will get a list of those files on the disk
- in DF0 (assuming there is a disk in there!)
-
-
- KILL filespec
- will delete the named file from the disk.
-
-
- INPUT "Which file(s) do you want to erase"; A$
- KILL A$
-
-
- It is recommended that you write your routines
- such that they first request for confirmation
- before deleting anything in order to check that
- you will not lose anything vital.
-
-
- NAME filename1 AS filename2
- allows a specified file to be renamed.
- filename1 receives the name that is specified
- as filename2; note that you can not swap names
- of files or have two files with the same name.
-
-
- CHDIR
- changes the default directory. This is helpful
- when using the FILES and NAME commands, and for
- using any newly created or modified files (see
- OPEN, BSAVE etc. later on).
- Your Amiga manuals will explain how the
- directory system works, but briefly: each disk
- drive you have (including a simulated disk
- drive created in the memory by the ramdisk)
- will can be referred to by its device name,
- e.g. DF0:, DF1:, DH0: etc. or by its volume
- name which is it is given when it is formatted.
- It is generally best to refer to files on disk
- by their volume name, that way the system can
- ask you to put the disk in the drive if it
- isn´t already there and it will prompt you to
- put your system disk back in when it needs it.
- On each disk you can store files in one large
- unstructured group, or choose to organise them
- into named directories. A directory is a type
- of filing system folder in which you can store
- those files that are pertinent to a certain
- subject. Each directory can have several sub-
- directories which again can be used to divide
- the information up into useful groups. Files
- with identical filenames can be stored in two
- different directories without causing any
- problems.
- For example you can have on a disk called WORK:
- a directory called ACCOUNTS which can in turn
- have two sub-directories - OFFICE and HOME. A
- file called LETTER in the latter sub-directory
- can be accessed by the pathname:
-
-
- "WORK:ACCOUNTS/HOME/LETTER"
-
-
- The pathname of the file tells the computer the
- route it will have to take through the various
- directories to access the data.
- Using the CHDIR command you can make the sub-
- directory DF1:ACCOUNTS/HOME the current
- directory. Files held there can then be
- accessed by their short name only and commands
- such as FILES will operate on that specified
- sub-directory if just a filename is used.
-
-
- MKDIR pathname
- creates a new sub-directory from within the
- current default drive and directory or via a
- specified pathname.
-
-
- RMDIR pathname
- removes an existing named directory as long as
- it contains no files at the time.
-
-
- Reading and Writing Disk Files
-
- All computers need a system for permanently
- storing the information that the user has
- entered, whether this is a program, a list of
- names and addresses, a screen picture or
- whatever.
- Manipulating data files on disk is one of the
- most important jobs your computer can do. Data
- storage is increasingly what computers are
- about, as the development of appropriate
- hardware such as hard disks drop in price so
- computer languages are developing to make it
- easier for the user to access and use data held
- in a permanent record. There are however
- different types of disk file that can be used,
- each appropriate to different circumstances.
- The simplest type of disk data file you can
- create is a completely unstructured record of
- the contents of a specified part of the
- computer´s memory. The most frequently used
- example of this technique is when a graphical
- image on the screen, made up from a pattern of
- dots held in memory, is saved for later recall.
- The way screen pictures are stored and the
- implications of this technique are detailed in
- the section on The Screen.
- The keywords we use for writing and reading
- simple memory-image files are BLOAD and BSAVE.
- To understand how these commands work we must
- learn something about how the computer´s memory
- is structured.
- Every item, or byte, of data (which is large
- enough to store one single letter of a text
- string for example) is stored at a specified
- memory address. The amount of memory available
- varies - on a standard A1200 the number is
- 2*1024*1024 bytes (a kilobyte is 1024 bytes
- rather than a thousand, because of the way that
- computers work internally with binary
- arithmetic, a megabyte is 1024 kbytes).
- Not all of memory will be free to use for data
- - many locations store important working space
- for the operating system and the programs that
- are currently loaded.
- The syntax for BSAVE and BLOAD is:
-
-
- BSAVE "filename", start_address, length
- BLOAD "filename", start_address
-
-
- The filename can contain a drive identifier and
- sub-directory path.
- The restrictions on the use of filenames is
- rather complex (see your Amiga Manual for an
- exhaustive list) and it is important to ensure
- that your program contains a suitable selection
- of routines to trap nonsense entries by the
- user.
- As an alternative to memory-image files it is
- also possible to define much more highly
- structured files that hold text and numeric
- data in special formats such that the computer
- can at the very least distinguish the length of
- each entry and its position within the file.
- The data within such files consists of
- individual items, normally known as records. It
- is possible to add or extract specific items of
- information from these files or to add data
- items of data to them.
- There are actually two types of structured file
- you can use with MaxonBASIC. The first is known
- as a sequential file and it holds data that the
- computer can only access by stepping through
- item by item in sequence. For example, you can
- read the twentieth record in the file only by
- first reading records 1 to 19. The advantage of
- such a sequential system is that each
- individual item of data can be of any length or
- form that you desire, provided that the end of
- that particular item is signalled somehow,
- whether by a comma, by quote marks ("), by
- carriage returns, or a combination of these.
- The second type is a random access file. This
- uses a system whereby each record of data is of
- a preset and rigid length and form (and we will
- see later that any data that is not of the
- right type has to be converted to match) such
- that the computer can automatically calculate
- the position of item number 20 and jump
- straight there - hence the name random access.
- Because random access files contain items of a
- preset length, old data can safely be
- overwritten by new without any danger of
- obliterating the next entry. Sequential files
- can only have new data added to the end of
- existing files. To remove or insert existing
- items, an old file must be copied item by item
- into a new file, with the appropriate
- modifications made during the process.
- Random access files are therefore often very
- much faster in practice (although this does
- depend on the use to which you are putting
- them). They have the disadvantage that they can
- be more wasteful of disk space - all records
- must be allocated the same room regardless of
- their actual length; this in turn is determined
- by the longest entry you have to accommodate.
- The type and structure of a data file is
- defined when it is created, and this is done by
- the OPEN command. It is no surprise then that
- this can be a rather complicated keyword with
- several parameters:
-
-
- OPEN file_spec [FOR mode] AS [#]channel_num
- [LEN=record_size]
-
-
- MaxonBASIC can have 255 files open at once, so
- it is fundamental that each of these files is
- designated by a number as it is opened. Any
- future disk reading or writing commands can
- then be told the file they are to work on by
- referring to that number. Assigning the number
- is done by using the AS # part of the OPEN
- command.
- A simple
-
-
- OPEN "filename" AS #n
-
-
- command will create a new sequential access
- file, or open an existing one of the given name
- for reading and modification.
- However it is possible to define the particular
- type and nature of the file that has been
- opened using the following commands:
-
- OPEN "name" FOR OUTPUT AS #2
-
- a sequential file for writing.
-
- OPEN "name" FOR INPUT AS #9
-
- a sequential file that is to be read.
-
- OPEN "name" FOR APPEND AS #1
-
- a sequential file that already exists and is to
- have data added to the end.
-
- OPEN "name" FOR RANDOM AS #5
-
- a random access file
-
- The final option is LEN=number.
-
- This sets the length of each entry in a random
- access file. The default size, if the command
- is omitted, is 128 bytes long. If this command
- is used for sequential files, it controls the
- size of the memory buffer that has to be filled
- before any data actually gets written to disk.
- Disk operations such as writing data are, in
- computer terms, relatively slow. The Amiga very
- sensibly waits until it has a reasonable amount
- of data to write before it goes to the trouble
- of moving the disk drive heads around etc.
-
-
- Sequential Files
-
- Putting data into a sequential file, and
- retrieving the data from such a file, in many
- ways parallels the system used for reading
- information from the keyboard, and writing to
- the screen or printer. Indeed so similar are
- the operations that the keywords used are
- almost identical.
- INPUT# and LINE INPUT# allow data to be read
- from a sequential file. As with input from the
- keyboard, INPUT # reads data that is to be
- assigned to a specified list of variables. LINE
- INPUT# reads an entire line of a sequential
- file until it reaches a carriage return
- character, ignoring any commas or other data
- delimiters and assigning the result to one
- string.
- INPUT$(x) can read x bytes of data from either
- a sequential or a random access file regardless
- of any data separators or field boundaries it
- crosses in doing so.
- As we have seen, putting data into an existing
- sequential file can only be done by adding it
- to the end of those records already saved. The
- keywords to use to do this are WRITE#, PRINT#
- and PRINT# USING.
- As with output to the screen, WRITE#
- automatically separates different data items
- with commas, and encloses strings within
- quotes. The full options available with the
- PRINT# and PRINT# USING commands, and the
- others, are detailed in the Command Reference
- chapter. When used to write data to a file they
- create an exact image of the information that
- would be seen on screen so certain mistakes are
- possible if you are not careful.
- For example:
-
-
- PRINT#1, 1,2,3,4,5
-
-
- will assume that the commas are to be replaced
- by spaces as on the screen. If the items were
- intended to be stored as separate data items
- the commas have to be PRINTed explicitly as in:
-
-
- PRINT #1, 1;",";2;",";3;",";4;",";5;
-
-
- is probably best used for producing formatted
- lines of text that are to be retrieved by the
- LINE INPUT# command, or for storing formatted
- numbers as produced by PRINT# USING.
- Note the distinction between a PRINTed, and
- therefore formatted, line of text, as would be
- produced by a word processor for example, and a
- structured text file such as may be produced
- by, say, a database using the WRITE command. In
- the former case the output will look more
- meaningful to an observer, but the computer
- itself will be unable to determine what each
- individual item of data represents, and where
- one data entry ends and another begins. In the
- latter case every item of data is clearly
- separated from the next by commas and quotes.
- The WIDTH# keyword can be used to limit the
- maximum length of any one line of data that is
- PRINTed to the file.
- Try the following example:
-
-
- A$ = "John Smith"
- B$ = "21 New Road"
- C$ = "London"
- OPEN "WRITE.DAT" FOR OUTPUT AS 1
- WRITE #1, A$, B$, C$
- OPEN "PRINT.DAT" FOR OUTPUT AS 2
- PRINT #2, A$, B$, C$
- CLOSE #1, #2
-
- REM Now read using LINE INPUT
- OPEN "WRITE.DAT" FOR INPUT AS 1
- OPEN "PRINT.DAT" FOR INPUT AS 2
- LINE INPUT #1, A$
- LINE INPUT #2, B$
- PRINT "WRITE data looks like:"
- PRINT A$
- PRINT : PRINT "PRINT data looks like:"
- PRINT B$
- CLOSE
-
-
- The file called WRITE.DAT will have the data
- stored internally like this:
-
-
- "John Smith","21 New Road","London"
-
-
- The file called PRINT.DAT will have data stored
- internally like this:
-
-
- John Smith 21 New Road London
-
-
- Any data stored using the PRINT # keyword can
- be formatted within the file in the same way as
- it can on the screen:
-
-
- PRINT #2, A$; B$; C$
-
-
- would produce a file containing
-
- John Smith 21 New Road London
- whereas:
-
-
- PRINT #2,A$
- PRINT #2,B$
- PRINT #2,C$
-
-
- will produce a file like this:
-
-
- John Smith
- 21 New Road
- London
-
-
- Of course each of these different formats can
- be accessed in different ways with the INPUT#
- and LINE INPUT# commands. For example, using
- the first example file produced with the WRITE#
- command:
-
-
-
-
- OPEN "WRITE.DAT" FOR INPUT AS 1
- INPUT #1, A$
- PRINT A$
-
-
- would produce the result:
-
-
-
-
- John Smith
-
-
- whereas:
-
-
-
-
- OPEN "WRITE.DAT" FOR INPUT AS 1
- LINE INPUT #1, A$
- PRINT A$
-
-
- will produce the result:
-
-
-
-
- "John Smith","21 New Road","London"
-
-
- The LINE INPUT# command has ignored the data
- separators and has read a whole line from the
- file into the variable A$. Conversely in the
- case of the first PRINT example:
-
-
- OPEN "PRINT.DAT" FOR INPUT AS 1
- INPUT #1, A$
- PRINT A$
-
-
- would produce the result
-
-
-
-
- John Smith 21 New Road London
-
-
- The INPUT # keyword has found no recognisable
- data separator to denote where one entry
- finishes and the next begins and:
-
-
-
-
- OPEN "PRINT.DAT" FOR INPUT AS 1
- LINE INPUT #1, A$
- PRINT A$
-
-
- would produce the same result.
-
- Obviously, different techniques are required
- depending on how you choose to store data from
- within your programs.
-
-
- Random Access Files
-
- When using random access files things are
- rather different. The rather inflexible format
- with which these files are stored requires a
- much more complex system of data manipulation
- before the information can be stored on, or
- retrieved from, disk.
- To recap, random access files are divided into
- records, but these are of a fixed length,
- defined at the time the file is opened, and can
- only contain data in a fixed format (actually
- stored as binary data) whether it started off
- as text or numbers of any precision. Many
- different keywords are therefore required to
- convert the data into the specified length and
- the required form.
- Random access files have one or two other
- important traits. Firstly the data held within
- a given record can in, turn, be subdivided into
- a series of fields each of which hold a subset
- of information that is pertinent to the whole
- record. For example, in a club mailing list
- file, each member would merit a record of their
- own, but within that record there will probably
- be a field for NAME, one for ADDRESS, one for
- TELEPHONE NUMBER etc.
- The keyword FIELD is used to allocate space
- within the total record to each sub-division:
-
- FIELD 1, 20 AS name$, 50 AS address$, 12 AS
- tele$
- Each string variable that is defined in the
- FIELD statement is called, of all things, a
- fielded variable. Fielded variables are rather
- special and should only really be used in
- conjunction with the RSET and LSET commands
- that we have already met, in order to produce a
- precisely-formatted string. Data can not be
- allocated to these variables using other
- commands such as INPUT or they will lose their
- ´fielded´ status.
- A FIELD statement must be issued before reading
- or writing a random access file. Even if the
- records are not subdivided, at least one field
- string must still be defined to hold the data
- that is to be written to the file.
- Because all data held within a random access
- record has to be of the defined length then if
- it is too long it will be truncated and if it
- is too short it has to be padded out to fit. To
- do this all data is converted to a string form
- of the required length, before being saved. To
- recover it again it has to be converted back
- from a string to the data form it originally
- started with.
- The process of writing data to a random access
- file is therefore as follows. Firstly all
- numeric data has to be converted to a string.
- The following keywords do this job:
-
- MKI$(x) converts an integer x to a string.
-
- MKL$(x) converts a long integer x to a
- string.
-
- MKS$(x) converts a single precision number x
- to a string.
-
- MKD$(x) converts a double precision number x
- to a string.
-
- The next step is that the resulting string has
- to be placed in the random access buffer, an
- area of memory automatically reserved as
- workspace when the file is opened, ready for
- writing to the disk. As this is done the data
- is padded to the length required to fit either
- the whole record or a field to which it is to
- be assigned. This is done through the use of
- the keywords LSET or RSET. LSET fits the given
- string to the left hand end of a padded string
- of the required length. RSET fits it to the
- right hand end of a padded string of the
- required length.
-
- For example the command:
-
-
- RSET A$=MKL$(x)
-
-
- will fit the string equivalent of the long
- integer variable x, into the right hand edge of
- the fielded variable (A$) ready for storage.
- If the name of the variable, A$, has been
- designated as a field occupying a subsection of
- the total record length (see above) the
- computer will automatically store the data in
- the correct place within the total buffer. In
- this case RSET or LSET will place the data into
- the right or left hand end of the room
- allocated to that variable.
- Remember that MKtype$ is only necessary when
- storing numeric data. Commands such as:
-
-
- RSET A$=B$
-
-
- or:
-
-
- RSET A$="Fred Smith"
-
-
- can be used to place text data directly into a
- fielded variable.
- When all of the fielded variables have been
- assigned the appropriate data, or left blank if
- required, the buffer memory can be copied onto
- the actual disk.
- The command required is n, x, which writes the
- current value of the buffer data to the correct
- place within file number n, as record number x.
- If x is omitted the next record in the file is
- written. The buffer is ´emptied´ as a result of
- this command so that the next record to be
- written will be starting with a clean sheet, as
- it were.
- That was many new concepts to take in, but the
- process is really very simple if you take it
- step by step. Here is a simple example:
-
-
- A$="John Smith"
- B$="21 New Road London"
- X%=21
- OPEN "PERSONAL.DAT" FOR RANDOM AS #1 LEN=65
- FIELD 1, 20 AS name$, 40 AS address$, 5 AS age$
- LSET name$=A$
- LSET address$=B$
- LSET age$=MKI$(X%)
- PUT 1,1
-
-
- Retrieving data from a random access file is a
- slightly simpler process. The opposite of the
- PUT command is GET. Before issuing this
- command, the field variables should again have
- been declared in the program. Once one record
- has been read these fielded variables can then
- be used immediately, for example to print
- individual sections of the data, or the
- retrieved data can be assigned to other
- variables for manipulation freeing the fielded
- variables for reading another record.
- If the data that has been retrieved was
- originally assigned to a numeric variable it
- can be converted back to its original form
- using one of the following commands.
-
- CVI(string$) converts the data back to an
- integer.
-
- CVL(string$) converts data back to a long
- integer.
-
- CVS(string$) converts data back to a single
- precision number.
-
- CVD(string$) converts data back to a double
- precision number.
-
- Note that these commands work in a very
- different way to the VAL keyword, and they
- cannot be used in its place. Note also that
- random access files require that you can
- anticipate the likely precision of numbers
- before they are converted. Sequential files are
- more tolerant in this respect - a numeric
- variable of an unspecified type can be used to
- hold a given value and that variable will to an
- extent adjust its internal format to match the
- data it is assigned.
-
-
- OPEN "PERSONAL.DAT" FOR RANDOM AS #1 LEN=65
- FIELD 1, 20 AS name$, 40 AS address$, 5 AS age$
- GET 1,1
- PRINT name$; CVI(age$)
-
-
- will produce the output
-
-
- John Smith 21
-
-
- Note that the variable name$ is padded with
- spaces to the length defined in the field
- statement; you can use RTRIM$ to cut this data
- down to size.
- Finally we have the keywords LOF, LOC and EOF
- which are three functions that allow the
- program to keep track of the size of a file and
- the current position of the pointer within it.
- LOF stands for Length Of File (in bytes).
- LOC stands for the LOCation of the data
- pointer. When using random access files it
- reports which number entry was read by the last
- GET command or was last written to by PUT. For
- sequential files LOC is often less useful. It
- returns the current byte position of the file
- pointer divided by 128. If your records are of
- a set length the actual record pointed to can
- be calculated from this value even if your data
- entries are longer or shorter than 128 bytes.
-
- EOF, standing for End Of File, is an invaluable
- logical function that reports TRUE (-1) when
- the data pointer has reached the last data
- entry. It is usually used in logical loops to
- trigger the end of a certain operation as in
- this example which reads an ASCII file and
- copies it to the printer:
-
-
- SUB Print_File
- FILES
- INPUT "Which file do you want to print?"; A$
- OPEN A$ FOR INPUT AS #1
- WHILE NOT EOF(1)
- LINE INPUT #1,aline$
- LPRINT aline$
- WEND
- CLOSE #1
- END SUB
-
-
- Shutting down a file is a very simple affair -
- just use the command CLOSE for either
- sequential or random access data files. A list
- of numbers can be given to close several files
- at once, and the keyword CLOSE without any
- specified numbers shuts down all files.
- The keyword RESET has the same effect. All
- FIELD statements are forgotten at the same
- time. The various program termination commands
- STOP, END and SYSTEM also automatically shut
- down all files.
- All OPENed files must be closed if the disk is
- to be removed while the program is running or
- data may be ruined. At the very least any data
- still held in memory buffers will be lost.
- Because of the threat of power cuts you can
- consider including a routine in all your
- programs that, perhaps at a timed interval,
- makes a backup copy of the current files.
- The final command that may be of value is the
- keyword VARPTR#. This will return the address
- of the buffer used to store information that
- has just been read from, or just prepared for
- sending to, the file number. This keyword is
- principally designed to pass information to
- routines written in other languages such as
- assembler to allow them to access the data held
- by your MaxonBASIC program.
-
-
- Error Handling
-
- Error Handling is a means whereby the
- programmer can anticipate, and make allowance
- for, undesirable circumstances whilst the
- program is running. These ´errors´ are of three
- main types. They may result from a problem in
- the hardware such as no paper in the printer,
- no room left on the disk or no disk in the disk
- drive. They may follow an incorrect data entry
- or response by the user. Finally they may be
- triggered by some error in the programming that
- did not become apparent under test.
- MaxonBASIC, in conjunction with the Amiga
- operating system can pick up, and determine the
- nature of, a wide selection of errors and it is
- good practice that your program should try to
- prepare for as many of these as possible. Error
- trapping routines can be tedious to plan and
- write, and can seem to take a disproportionate
- amount of time compared to the real nuts and
- bolts of your program, but if done well they
- are the hallmark of a professional quality
- program.
- We have already seen how it is possible to
- enter simple error traps by specifying certain
- logical conditions that accept or reject data
- entered by the user. For example:
-
-
- DO
- LOCATE 1,2
- INPUT "Size of curve (1-4) ",s%
- y%=length/s%
- LOOP WHILE s%>=1 AND s%<=4
-
-
- This continues to ask the question until the
- user puts on his spectacles and provides an
- acceptable answer. Note also that the variable
- s% is an integer type so that an entry such as
- 1.4 would be converted to a usable number.
- However, it is part of the nature of error
- catching routines that there are always more
- possible ways that the user can catch you out
- than you will ever anticipate in the first
- attempt; let´s say he enters the value 0 -
- you´ve forgotten to trap this and you will get
- a runtime error on the fourth line because of
- division by zero.
- It is also inevitable that ´errors´ can occur
- that you will be unable to prevent happening,
- such as an unformatted disc being placed in the
- disc drive and so on. We therefore need a
- system of dealing with such errors no matter
- when and how they occur.
- Errors that are produced through a problem in
- the hardware or through a mistake in the
- program, such as trying to divide an expression
- by a variable which has somehow been assigned a
- value of zero, will generate an error number
- specific to that particular situation.
- To allow the maximum use of this facility there
- are a range of functions that will report the
- nature of the error, together with the line
- number which was being executed when the
- problem occurred. ERR is the function that
- returns the error code and ERL returns the line
- number where it happened. From these your
- routines can deduce what the problem was and
- decide how to fix it (e.g. print a message such
- as There is no disk in the drive and then
- restart the data input routine).
- The nature of errors means that they can only
- be anticipated to occur at un-anticipated
- times. Similarly the response to the error has
- to be ready to come into operation at any time.
- Hence error handling really has to be organised
- as a background event trap.
-
- The command sequence we use is therefore is ON
- ERROR GOTO which causes a jump to a specific
- line number or line label as soon as any error
- occurs. The line that is jumped to will usually
- be the beginning of a routine that decides
- exactly which error has occurred, deals with it
- in some way, and decides where (if at all) that
- the program is to resume execution.
- The keyword RESUME specifies which line number
- or line label the program is to return to
- following the specific error correction routine
- has been completed.
- Here is an example:
-
-
- a$="TEST.DAT"
-
- Kill_File:
-
- ON ERROR GOTO Kill_Problem
- KILL a$
-
- ON ERROR GOTO 0 ´ Normal error reports
-
- STOP
-
- Kill_Problem:
-
- ErrNum=ERR
- REM Can´t use ERR directly in CASE
-
-
- SELECT CASE ErrNum
- ´Error 53 is File not Found
- CASE 53
- FILES
- PRINT a$;" not found"
- INPUT "Please give a valid file";a$
- CASE ELSE PRINT "Fatal error ";ERR : STOP
- END SELECT
- RESUME Kill_File
-
-
- As an extension of the error facility the
- programmer can also add to the list of errors
- that will be reported by specifying new
- conditions that are to be regarded as problems
- of some kind. The keyword ERROR can be used in
- this context to define the error that is
- required. It can be used to extend the range of
- conditions under which an existing error number
- is triggered:
- For example: runtime error 5 is Illegal
- Function Call - you might want to use that in
- one of your own user-defined functions as shown
- on the next page:
-
-
- REM Factorials by iteration
-
- FUNCTION Factorial#(x)
- STATIC Temp#,i
-
- REM Can´t do 0! or 1!
- IF x<2 THEN ERROR 5
-
- Temp#=1
- FOR i=2 to x
- Temp#=Temp#*i
- NEXT i
- Factorial#=Temp#
- END FUNCTION
-
-
- The ERROR keyword can also be used to define
- the conditions that would trigger an error
- number that has not previously been used. This
- is invaluable when using unusual peripherals
- for which there are no pre-defined errors, and
- can even be used to catch situations such as
- when a data input has exceeded a permissible
- maximum, or is not of the appropriate format
- etc.
-
-
- Get_Input:
-
- ON ERROR GOTO Validate
- INPUT "Choice (1-4)";Choice
- IF Choice<1 OR Choice >4 THEN ERROR 200
- INPUT "Name, please"; Name$
- IF LEN(Name$) > 19 THEN ERROR 201
-
- REM Normal error reporting
- ON ERROR GOTO 0
-
- Validate:
- ErrNum=ERR
- SELECT CASE ErrNum
- CASE 200
- PRINT"Please select a number between 1 and
- 4"
- CASE 201
- PRINT "Names must be less than 20
- characters"
- CASE ELSE PRINT "Unknown validation error" :
- STOP
- END SELECT
- RESUME Get_Input
-
-
- This routine most usefully works in conjunction
- with an ON ERROR statement as the newly defined
- number can then, if triggered, cause a jump to
- a sub-program which will print an explanatory
- comment. If error handling is not enabled the
- effect of the newly defined error, when
- triggered, is to print the message Runtime
- error nn where nn is the error number.
-
-
- End Sub
-
- That was a tour of the concepts that underlie
- MaxonBASIC. Hopefully it has provided you with
- a good enough grounding to begin to experiment
- with the various commands in detail.
- There are several ways to expand your BASIC
- programming skills.
- Firstly practice. You will get a feel for how
- the different commands work by trying them out
- in routines of your own devising.
- Secondly type in routines from magazines and
- books (you will be pleasantly surprised by how
- many listings work in MaxonBASIC with only the
- minimum of modification so you do not even have
- to restrict yourself to Amiga programs). There
- is never one correct way of programming a given
- task, any dozen people would probably come up
- with a dozen different solutions to a given
- problem. Entering listings is therefore an
- invaluable way of learning new ways of looking
- at things.
- Remember, you do not have to re-invent the
- wheel every time you sit down at the keyboard.
- Many routines have already been created that
- can be used within your own programs, probably
- with greater speed or using less memory space
- than you would have been able to come up with
- on your own.
- The bibliography lists a selection of books
- that may be useful in teaching programming
- techniques.
-
-