Subject: GFA Tutorial, Month One By: James Collett (Professor) A Member Of: VIRTUAL INFINITY Email: s6005146@oxpoly.ac.uk (or s6005146@brookes.ac.uk) Address: Room N4, L.S.C.Collage, Wheatley, Oxford, OX9 1HX Mono accnt.: bcc Introduction To Syntax And Structure ==================================== In the same way 'human' or natural languages have syntax & structure, computer languages do too; and natural language syntax & structure provide a good analogy for computer languages: Syntax is far more than just saying sentences must contain words and sentences must start with capital letters. It is a complete set of rules, in theory unambiguous, which can be used to determine whether a sentence is valid or not. For example "The built a was tamer fortune blaze by lazy." contains words and starts with a capital but would not be considered a valid sentence! An example of simple syntax rule would be sentences may consist of 'determiner + adjective + noun': "The brown fox." In a similar way that syntax varies from natural language to natural language (e.g. English and French), syntax also varies between computer languages (e.g. GFA Basic and C++). If we want a particular program to work, we must ensure the syntax is correct. In the natural language called English, structure is the way that sentences are fitted together into paragraphs, and paragraphs fitted together with a heading at the top/etc to form documents, letters, etc. (Both syntax and structure will be discussed in more detail this month.) Variables ========= Throughout this tutorial I will try to indicate instructions with an asterisk (*) to distinguish them from information. * From low res, load GFA Basic and press for direct mode: A very important aspect in programming is being able to store and manipulate numbers and text. Places where data is stored are called variables but can be thought of as 'draws', where each draw has a label and a contents. You can think of GFA Basic having an infinite number of draws (it`s not quite, but it`s a hell of a lot!) and when you first load the language all these draws are unlabelled and empty. To label a draw, for example age, and put an age in it type: * age%=19 To label a new draw, for example surname, and put a name in it type: * surname$="Professor" Note that integer (whole number) variables (or 'numerical draws') are identified with a percentage sign and string variables (or 'text draws') are identified with a 'dollar sign', which is also called string. I.e. you would pronounce these two variables 'age percent' and 'surname string'. Note also that strings must be enclosed in double quotes ("), this is not part of the string but indicates where it starts and finishes. Two simple commands used to manipulate variables are PRINT and INPUT, note that commands do not have to be entered into GFA in capitals, but throughout this tutorial I will try to put them in capitals to identify that they are commands. PRINT is used to output to the screen, to find out the contents of the variables (or 'draws') type: * PRINT age% * PRINT surname$ INPUT is used to input, from the keyboard, a value (number) or string into a variable. Try: * INPUT age% * INPUT new_value% GFA should prompt for a number in each case. After entering, type the following, followed by your name at the prompt: * INPUT surname$ Note that when you put your age into age% the previous contents are completely destroyed; similarly for surname$. Check this out by typing: * PRINT age% * PRINT surname$ * PRINT new_value% PRINT can also be used directly with values and strings (text) as well as with variables ('draw' labels). Typing long commands every time can be very laborious and most commands have abbreviations or short hand versions. The abbreviation of PRINT is simply ?. Try some of the following, using both PRINT and ?: * ? 7 * ? 7-2 * ? age%+14 * ? "Hi there!!" * ? "Hi there "+surname$+"!!" * ? age%+new_value%+2 As well as using plus (+) to return results to screen, it can also be used to store results as variables. Try this: * new_value%=age%+3 * ? new_value% * age%=age%+1 * PRINT age% * surname$="Hello "+surname$ * ? surname$ Note that + has a different purpose depending on whether being used with strings or numbers. If you try and use it with a mixture of both then you will get an error - i.e. GFA syntax rules have been broken! Instead you must use a semicolon (;) as follows: * ? surname$;" is ";age%;" years old" * ? surname$;" will be ";age%+1;" next year" You can also use minus (-) to subtract, asterisk (*) to multiply and slash (/) to divide numbers, although obviously not strings! So in summary: Strings = Use + to 'add' strings, to screen or a variable Integers = Use + - * / to manipulate, to screen or a variable Both = Use ; to 'mix' strings and integers, to screen only Before we write our first program, note what happens if you try to put a string in an integer variable (or integer 'draw'), and vise-versa: * surname$=19 * age%="Professor" Note also what happens if you try to put a real number (number with decimal point) into an integer: * new_value%=-6.54321 * PRINT new_value% Our First Program ================= Another note just before we write our first GFA program: if you have just started programming (maybe today!) I hope you can appreciate, when you start looking at any sources, you will come across things you haven`t learned yet and have to take as true or trust the programmer. I think it is important to show some demo sources as quickly as possible, thus there maybe one or two lines you`ll just have to trust me on for the minute! * Press to return to the editor and Merge VARIAB_1.LST: Before we Run (execute) the set of instructions lets manually go through them (or 'dry-run' them). First of all a message will be displayed asking for a name and then INPUT surname$ from the keyboard. After getting age% (presumably in years), it is multiplied by 12 to convert into months. The program then greets the person, and informs them of their age (now in months!) before ending. Note that the first two output lines end with a semicolon but the last output line doesn`t; if no semicolon is present on the end of a PRINT then GFA will automatically start a new line (i.e. LF+CR), if you wish to continue on the same line then you must include a semicolon. * Run the program by either pressing the appropriate function key or clicking on the appropriate menu button. Enter a name and age of your choice. If you don`t trust the output (why not?!?) then, after ending, goto the direct mode, check the result by multiplying the input age by 12 and return to the editor. Note that the 'run screen', at the point when execution stopped, appears as the 'backdrop' on direct mode. * Re-run the program a few times, try to predict what you would expect to happen if you input a number for the name or string for the age. Try also inputing negative numbers or real (decimal) numbers as the age. This program is very simple, but not bad for a first effort! Let`s try improving things: * From the editor Merge VARIAB_2.LST: DO NOT RUN THIS - IT WILL NOT WORK! Note that Merge [which loads an ASCII source] doesn`t wipe the previous contents. The advantage (or disadvantage!) of Load [which loads a 'tokenised' source] is it does wipe the previous contents and starts from scratch. The reason we have to use Merge, as already discussed, is to make this tutorial compatible with all versions of GFA. * From the editor select New to start from scratch, confirm your action and now Merge VARIAB_2.LST: I`ve added to this source an initial clear screen, then scraped the PRINTs and included user-defined prompts with the INPUTs. The GFA default prompt is a question mark (?). Note a comma is necessary to separate the optional prompt and variable. Next is the fastest method, in GFA, to multiply a variable by a value: MUL var,n is about 30% faster than var=var*n. There are similar commands to ADD, SUB and DIV (all will be dealt with in detail later). Moving to the output, after the CHR$ you`ll notice I`ve used semicolons instead of plus`s to allow 'mixing' of strings and numbers in a single PRINT statement. CHR$, again to be discussed later, returns (displays) the character of a given ASCII value. For example to display an "A", which has ASCII 65, type the following in the direct mode: * ? CHR$(65) * ? CHR$(7) ASCII 10 is LF and leaves a gap on screen. ASCII 7 (above) is BEL and sounds the ST`s bell. I personally do not like the standard GFA END command, which brings up the horrible alert box, and prefer to "finish off" myself by beeping, waiting for a key press (INP(2)) and returning directly to the editor. It`s a matter of personal preference and you may wish to beep, flash, print "Program Terminated" or a whole host of other things to indicate your own programs have reached their normal ends. As well as END and EDIT, there is also a STOP command which displays an alert box and returns to direct mode, STOP does also allow you to continue (if possible - i.e. stopped in middle) which is occasionally useful. Note in GFA 3 VOID can be abbreviated to ~. Thus I finish the majority of my GFA 3 programs with: PRINT CHR$(7); ~INP(2) EDIT VOID (discussed later) is mainly used with numerical functions (discussed later) to mean you wish to execute or perform a calculation but not hold the returned result. Sounds strange but very useful, for example wait for key press but not care which key is pressed. Comments And Annotation ======================= * From the editor select New, confirm and Merge COMMENTS.LST: It is often useful, especially with more complex pieces of source, to add comments (or remarks) and to annotate lines. GFA provides the single quota (') for an entire line comment and explanation mark (!) for annotation on, and after, a line to be executed. The text after the marker will be ignored during execution and can break every syntax rule in the book! The convention, however, is to high-light with asterisks but this depends on your personal preference. Variable Types ============== As well as being able to store and manipulate strings (text) and integers (whole numbers), GFA can also (hopefully obviously!) handle real numbers. In the same way integers and strings are respectfully identified with a percentage sign and string (dollar) sign, real numbers are identified with ... no sign! In summary: var$ = string (text) variable, contents marked with quotes (") when assigned to variable var% = 32 bit integer variable, range approx -2 billion to +2 billion var = real number, range VERY BIG and VERY ACCURATE The advantage of using integer over real, where real is not required, is that of speed - integers are faster that real numbers, but can only be used if no decimal is needed (e.g. a counter, discussed in more detail this month). GFA 3 also offers 16 bit integer (word) and 8 bit integer (byte) variables, which are even FASTER than a standard integer but with reduced ranges, as follows. During this tutorial I shall stick with 32 bit integers (long-words) so it is GFA 2 compatible: var& = 16 bit integer variable, range -32768 to +32767 var| = 8 bit integer variable, range only 0 to 255 Boolean Expressions - Introduction To Decision Making ===================================================== Another important concept in programming is that of branching, i.e. coming to a 'junction' and either going one way or the other - no buts or maybies! A boolean expression is one that is either TRUE or FALSE, for example either age% is 99 or it`s not 99, either surname$ is "smith" or it`s not "smith" - no buts or maybies. Considering numbers for the moment, as well as testing if a variable or value is identical to another, you can also test: > greater than < less than >= greater than or equal to <= less that or equal to <> greater or less than (i.e. not equal to) * Goto direct mode and type CLS to clear screen if required: In GFA, TRUE has the value (or 'is represented by') -1 and FALSE has the value 0. Try some of the following and try to predict the returned result (note they don`t have to be entered in capitals): * ? TRUE * PRINT 7>7 * ? FALSE * ? 7>=7 * ? 2=2 * ? (3+1)=(2*2) * ? 2=5 * ? 9<=(3+4) * ? 2<>5 * ? (9<=(3+4))=FALSE * ? 2<5 (As well as testing if a string is identical to another, there are other 'string tests', to be discussed in detail next month.) In GFA, to branch a way dependant on the 'truth' of an expression, we use IF ... ENDIF and IF .. ELSE .. ENDIF. * Return to the editor and have a look at BRANCH_1.LST and BRANCH_2.LST (don`t forget to New before you Merge!) As well as simple tests (e.g. <> or >=), combinations of tests can be made using the logic gates: AND, XOR (exclusive or), OR (and/xor) plus NOT; for example age%<99 AND NOT(surname$="smith"). I am not going to cover the complete set of 'truths' for all gates (called the 'truth tables') because they are even more boring than this tutorial (which does improve next month!) and are fairly straight forward anyway. *However, I have included a sample source, BRANCH_3.LST, and a truth table source, TRUTABLE.LST, to have a look at. You can use the latter if you need the table for a particular expression, and it is set up for '(NOT P) AND Q' where P and Q represent simple tests such as age%<99 or surname$="smith". After covering FOR and NEXT (this month) you`ll be able to add or remove simple test representatives as required. Note in GFA 3 an ELSE and IF can compress onto one line (shown right), thus meaning the second ENDIF and second indent are not needed. During this tutorial I shall stick with the GFA 2 compatible method (shown left): ELSE IF value%<10 ELSE IF value%<10 PRINT "Number ~~~~ PRINT "Number ~~~~ ELSE ELSE PRINT "Number ~~~~ PRINT "Number ~~~~ ENDIF ENDIF ENDIF Looping - Introduction And FOR ... NEXT Loop ============================================ It is often necessary in programs to repeat a particular part a fixed number of times, repeat while a condition (boolean expression) is TRUE or even repeat until one is TRUE. One way of doing this could be to laboriously enter the part of the source 500 times! The serious solution is to use a loop, i.e. to tell GFA to 'loop' around the part either a fixed number of times or in collaboration with a boolean condition. GFA Basic actually offers no fewer than four 'looping mechanisms' which allow solutions to be found to any problem where it is necessary (or might be necessary) to repeat part of a program: The first and simplest loop, called the FOR ... NEXT loop, uses a counter to repeat the part a fixed number of times - which could be once or a million times. * From a 'clean' editor Merge, look at and Run FORNXT_1.LST: The loop can be thought of as building a 'table', in this case from 1 to 5 (the maximum count), and each time the loop is executed the next slot in the table is 'ticked off'. This isn`t quite how it works, inside the processor, but a good way to think for a simple loop. Note the value of the counter when you leave the loop, after final execution. * Look at and Run FORNXT_2.LST, preferably in low res: It may be necessary to use a far more complex count mechanism or 'STEP' than just 1, 2, 3. For example 0.2, 0.4, 0.6 (STEP 0.2) or -0.5, -1.0, -1.5 (STEP -0.5). This source is a perfect demonstration of this, which uses the PLOT command to draw a circle point by point using sine & cosine waves [note this mathematical source can be replaced with one line; sine, cosine, PLOT and graphics will be discussed in detail starting next month]. Note also that speed and angle (theta) need to be real, the radius(`s) and origin only need to be round to whole number though. * Try experimenting with the parameters (or 'control variables'), now discussed in general: Parameters ========== [Going off at a tangent for a few minutes (and nothing directly to do with looping!) a brief word about parameters.] Parameters (also called operands) can be best thought of as 'switches' or, as I said before, 'control variables'. In the same way your TV/monitor has a stack of knobs on it (no innuendoes please!), anything from a single line or routine upto a procedure (discussed this month) or complete program can have 'knobs'. For example the parameter of the line PRINT "Hello" is "Hello" and the parameters of ADD c%,4 are c% and 4. If, in a routine or program, you have a size/etc that is constant (e.g. 4) then you could put 4 everywhere you need it or you could declare size% as 4 and put that everywhere. If you needed to change it for some reason, is it easier to change one size% or to search through the entire source and change all 4`s, hoping you don`t miss any and don`t change any 4`s which aren`t the size?? Listing all variable parameters together, towards the top of the program, saves you writing a complex user interface in your utilities at all and in final programs until the actual 'guts' are written and tested. (I never put proper user interfaces on my utilities - no need!) The use of (constant) parameters in programs will become more apparent with the use of more complex sources. * Experiment with FORNXT_2.LST`s parameters. Looping - Continued =================== * From a 'clean' editor Merge, look at and Run FORNXT_3.LST: Returning to the FOR ... NEXT loop, GFA also offers a DOWNTO facility, which is the equivalent to STEP -1 and cannot be used with other STEPs. Therefore in summary: If you need STEP -1 then use DOWNTO, If you need STEP 1 then use TO (without a STEP, 1 is default), And if you need any other STEP then use TO with a STEP ... obviously making sure you get the mincount and maxcount in the correct order whichever version you use! Note the value of the counter when you leave the DOWNTO loop, after final execution. * Look back at TRUTABLE.LST, mentioned above in Boolean Expressions. Figure out how the nested (i.e. one inside another) loops work, remembering the values of TRUE and FALSE (and not forgetting to New before Merging.) The next two loops are the REPEAT ... UNTIL loop and the WHILE ... WEND (endwhile) loop, which respectfully REPEAT UNTIL a boolean condition is TRUE and repeat WHILE one is TRUE (i.e. until it`s FALSE). These are excellent for any situation where you`re waiting for something to happen or waiting for something to stop happening, for example waiting for a valid input: * Look at and Run WHILE.LST: Typical use of a WHILE loop to repeat input until the variable stops being invalid. (Note LEN returns the length of a string, functions will be discussed next month.) * New, Merge, look at and Run REPEAT_1.LST: Note this collects the key press (test%) from INP(2), another function, instead of VOIDing or 'ignoring' it as seen in cases so far. This loop REPEATs UNTIL test% is ASCII 120, i.e. "x". The main difference between REPEAT ... UNTIL and WHILE ... WEND is, as can be seen, the positioning of the boolean test to determine whether to go around the loop again (or at all). In the REPEAT ... UNTIL loop, as the test is at the end you will always go around the loop once; if this isn`t wanted then the loop must be nested inside (placed inside) an IF ... ENDIF. In the WHILE ... WEND loop, as the test is at the start the loop will never be executed if it tests FALSE when you first hit the loop; for example, in WHILE.LST, you enter a valid name/age first time before the loop. The final 'loop mechanism' which GFA offers, and many other languages don`t, is the DO ... LOOP loop. The primary use of this is as an infinite loop, i.e. once you get in it`s impossible to get out without taking fatal measures! Sounds strange but useful for both testing unfinished programs and final programs with no exit (e.g. game or demo). * After Merging, look at and Run DOLOOP_1.LST: Once Run, don`t press reset! The way to break out of any GFA program that appears to have crashed or gone into an infinite loop is to simultaneously hold down CTRL, ALT and SHIFT. (If this fails for a crashed GFA program then do reset!) [Note this break facility does not work with the compiler (discussed later).] In GFA 3 you can also use DO ... LOOP as a REPEAT ... UNTIL, a WHILE ... WEND, or even a combination of these two: Unfortunately this is GFA 3 only. If you`re using version 3 then LOAD DOLOOP_2.GFA, otherwise LOAD DOLOOP_1.BAS. Note when you Load you don`t have to New first. Load and Save are the conventional way to store and re-call files, Merge and SaveA are conventionally used for appending (merging) and for 'inter-compatibility'. To GFA 2 users: DOLOOP_1.BAS is the same as DOLOOP_1.LST, but I couldn`t not let you try Load! And if you want to see what your missing you`ll just have to get a copy of GFA 3! To users with GFA 3: DOLOOP_2.GFA uses two boolean test representatives, P and Q, to show a combination of REPEAT ... UNTIL and WHILE ... WEND. Note, if doing this combination, the tests can be identical or can be different. In this example, 'P' determines whether the loop is executed the first time and 'P AND NOT(Q)' is the determiner after that. Building Other Loop Combinations ================================ GFA Basic also has an EXIT IF command which can be attached to any loop, including an 'infinite' DO ... LOOP in GFA 2. It is bad practice to use this and should be avoided whenever possible, but allows an 'EXIT IF boolean condition' to be added to DO ... LOOPs and FOR ... NEXTs plus extra control to be added to REPEAT ... UNTILs and WHILE ... WENDs. * Merge, look at and Run FORNXT_4.LST: After placing 120 (ASCII of "x") into key% and displaying the instructions, this source goes into a STEPped -1 FOR ... NEXT loop, which counts down the number of attempts left to hit the right key, using EXIT to 'jump' out the loop should key% be pressed before attempt% runs out. If the loop is left 'properly' then attempt% will have 'run out' (i.e. become 0); otherwise, by pressing the EXIT key%, attempt% will be left 'hanging'. This source shows one way of combining a FOR ... NEXT and REPEAT ... UNTIL. * Merge, look at and Run REPEAT_2.LST: This does exactly the same job as the previous, but by using a REPEAT UNTIL and combining attributes from FOR ... NEXT, it handles the attempt% counter better. There are *several* methods, even in GFA 2 and without an EXIT IF, to combine all three mechanisms into one basic loop should it be necessary. Introduction To Arrays ====================== Moving on, an array is simply a table of variables all of the same type (e.g. all strings or all reals). * Goto direct mode and type CLS to clear screen if required: 'Paper tables' or 'manual tables' (e.g. timetable) can be one dimensional (i.e. just have one column or one row) and can be two dimensional (i.e. have both rows and columns). In the same way, for the moment, computerised arrays can be one dimensional or two dimensional. To create a new one dimension (one column) array with 6 rows (numbered 0 to 5) type the following (remembering commands don`t need to be entered in capitals): * DIM value%(5) To display the contents of the first 'box' on the table ('box' 0) simply type the following, the value 0 should be returned: * PRINT value%(0) [[NOTE that some versions, as far as I know GFA 3 only, return an "array index to large" error. If this has happened to you it`s not because of my tutorial but a minor bug with Direct mode. To fix the bug simply return to the editor, New to clear, type 'DIM correct%(0)' in the editor, Run this line, return to direct mode, re-type 'DIM value%(5)' and continue from there. Please remember even a language as superb as GFA can only be 99% perfect!]] Note the contents of all 'boxes' in a new array are initially 0. To change the contents of the sixth 'box' ('box' 5), use one of the following just like 'normal' variables: * value%(5)=22 * INPUT value%(5) Array elements (or array 'boxes') can be treated just any other variables. Try some of the following, predict what`s happening: * value%(0)=3 * value%(1)=8 * ? value%(0) integer conversion is covered later.) The first procedure you would need is one to book somebody in. After a few months, with people constantly booking, and leaving, this database will become 'untidy' or 'patchy'. The book_in procedure will have to search through UNTIL it finds an empty room (OR finds both hotels are full). After inputing and somehow validating both name and dates, the procedure can allocate the room to the person, and also possibly work out their bill. The other main procedure you would need is one to 'vacate the room' in the database after the person has paid and is ready to leave. If you didn`t know the room number and only knew the surname, the program would have to search through UNTIL it found a match for surname$(). The procedures would then need linking using either a command-driven or menu-driven system. This simple demo of 'visualising' a multi dimensional array (for which I haven`t written a source) is *FAR* from complete as a hotel system and leaves many problems such as how to deal with advanced bookings or how to deal with several people with the same surname. And Finally =========== I have deliberately set this month`s tutorial at an elementary level to give anyone a nice, gentle introduction to GFA. I hope you found some of it (if not most of it!) too easy. Although I won`t actually be putting GFA through its paces until months 3 and 4, I do intend to move onto more advanced stuff next month (including my game, LightMaze!) and hopefully make the tutorial less 'wordy'. I am not going to include a summary list of everything you should be able to do after going through this tutorial; but have included both source and compiled, executable versions of a simple exam grade program, which includes most of what you should be able to do. * Load, look at and Run EXAMMARK. Experiment with the source and add an expansion of your choice for next month`s tutorial. ---END---