(<--Previous) Back to Index (Next-->)

FB n00b: Tutorial 6

Note: This tutorial is for absolute beginners. If you aren't an absolute beginner and you dislike the tutorial, that's too bad. If you are an absolute beginner and there's something you don't understand, read through the tutorial a second time. If you STILL have difficulties, e-mail me (TheMysteriousStrangerFromMars@yahoo.com) and I'll try to help you out. I do assume you at least have a decent knowledge of how to use your computer - if not, there's not much I can do for you. By the way, you'll need FreeBasic to use this tutorial - you download that at freebasic.net, so be sure to download and install it before doing this tutorial. Now start reading!

Clarifying some important points

By now it's pretty important that you understand ALL the topics discussed in the first five tutorials. As with most tutorial series, each tutorial builds upon the previous ones. If you do not understand the three things that every program contains, basic input, output, doing simple mathematical calculations with either of the two kinds of number variables, working with conditionals and loops, or procedural programming, PLEASE re-read the appropriate tutorial. It will become imperative that you have a thorough understanding of all these concepts in the future.

Today I'm going to clarify some important points, because though I've introduced you to a lot of the fundamental concepts you may still not understand just how important some of these concepts are. The things I've taught you exist in and apply to almost any HLL you will encounter, though of course the way you do it will be different. As you are learning, it's important to understand how all these ideas tie together, and how precise the definitions for everything are. Forgive me if I jump around from topic to topic - today is kind of the "cleaning up" day, because the previous topics have raised a lot of different and important questions. I try to answer a lot of them here.

Our main discussion topic today will be expressions, though I'm going to teach you about all the different types of symbols in a program. FreeBasic, like most compilers, compiles your program by parsing through it. What this means is, it looks at your program, one character at a time, and figures out how to divide the mass of characters into logical units. For one thing, whitespace (that is, spaces and carriage returns) are ignored; for another, FreeBasic is case-insensitive, meaning that "abc" and "ABC" are the same thing, as far as the parser is concerned (this applies to variable names and keywords ONLY - string handling is another story). Comments are also weeded out - they are useful only to we humans, but to the compiler they matter not one bit. Finally, the compiler has your program divided into units which you could refer to use "words."

For example the line 'Print "Hello, " + my_name' would be divided into the words "Print", ""Hello, "", "+", and "my_name". It then has to figure out from the context what each word is used for - in this case, Print is a command word, meaning that it does something. The "Hello, " is a constant string - that is, it's not a variable, and it doesn't change; it's just there. Since our command normally operates on strings, the + stands for string concatenation - not arithmetic addition. And if it's string concatenation, then my_name must be a string variable. And of course, if you get any of these wrong, then the compiler will realize there's a problem and, not knowing what to do, will refuse to compile the source and usually tell you precisely what the error is.

If your program goes through that part of the compiler without any problems, the result is an assembly program. Assembly is a language that is very similar to machine language. Yes, it's possible to write a program in machine language, but it would be enormously masochistic - so the solution is to create something called an assembler, which converts mnemonics into machine language. The mnemonics are much easier for a human to understand, and still a lot easier to convert to machine language than a HLL, since each assembly mnemonic can be directly converted to a machine language byte code (as opposed to an HLL, which contains many commands that do not exist in machine language, for example Print, and furthermore is generally designed so it can compile for different platforms or operating systems - where generally it is impossible to do so with assembly, since everything is done differently depending on the operating system you're working in). The assembly code generated by FreeBasic goes through an assembler, and of course if there are any errors the assembler will refuse to work - but usually the compiler catches them long before it gets to the assembler.

What is the point of all this? After all, it's not likely you're planning to learn assembly language (though I recommend you do, if you ever have some free time - learning assembly has given me more insights into how my computer works and how to write a HLL program well than anything else I've ever learned), right? The main reason I did all that is to show you that not every "word" means the same thing to the compiler. Print, which is a command, is a different thing from my_name, which had better be a string variable since there is no command or keyword by that name. In fact, there is even a difference between your keywords - things like If, Do, Loop, While, and others - and your commands - Print, Input, Str, Chr, Val, etc. That's because the commands are really functions or subs in the standard library, and the exact way they work internally will vary depending on your operating system - whereas keywords like If, Do, Loop, and the rest work about the same and generally can be converted pretty closely to assembly code which is generally the same on all operating systems.

But there's a different kind of division I want to really emphasize today and that is expressions. These are something you've already learned about, but in a much more general sense and with no mention of the actual name. Expressions are the conditional part of your If, Select Case, Do, Loop, While, or For blocks. They are also the thing on the other side of the equal sign when you perform a mathematical calculation. For example:

  Loop While this_number <> 0

  If this_number <> 0 Then
    that_number = this_number * the_other_number + something_else
  End If
OK, so ignoring the fact that this program is nonsense... there are three expressions in this program, can you spot them? If you said "this_number <> 0", "this_number <> 0", and "this_number * the_other_number + something_else" or something similar, you were right. Those are expressions. Note that an expression always returns a number. You can put it in parentheses to clarify this point: Loop While (this_number <> 0). Sometimes you'll have a compound expression, one that is actually made up of several. These are joined by And or Or, and occasionally a few other things. You can group in any way with parentheses, just like in mathematics, only you can't use square brackets [] like in mathematics. Just remember that the order matters more than you might think.

Expressions, in the case of conditionals, are all about basic logic. You should have learned this stuff in high school math - my geometry course covered it, so should yours. You know, you've got a couple expressions and you try to see what you can infer (or deduce) from those two expressions. Sometimes you have more than that, but the point is you have to figure things out from this. That's the foundation of proofs, as well as boolean logic. I'm sure you remember boolean logic - Or, Xor, And, Not? Written differently, sometimes, but you must remember. Generally, you assign a value to a statement: 1 or 0. 1 means it's true, 0 means it's false. This just so happens to coincide with binary numbers, which we will be studying in the next tutorial, but that's beside the point. In geometry, you need to figure out whether one expression is true by analyzing one or more other expressions involving the same variables. In conditional expressions, we don't have to figure anything like that out - the computer does the calculations in the expression and checks if it's true or not. If it's false, 0 is returned, and the conditional doesn't work (that is, it goes to Else or exits the Loop, depending on where it's being used). If it's true, any non-zero value is returned. This can be 1 or any other number, but usually -1 is used. The reason is the way -1 is stored (which you'll learn in the next tutorial): -1 is stored by setting all bits in a variable to 1 (of course, the number of bits depends on the size of the variable, but that's beside the point).

Because conditional expressions work logically, you can use the standard And, Or, Xor, and Not. For example, the two conditional blocks below are identical.

  If Not (a = 0) Then
  End If

  If (a <> 0) Then
  End If
And so are:
  If Not (a > 0) Then
  End If

  If (a <= 0) Then
  End If
If you think about the expressions in both cases, you'll find that this is so, for any value of a. There are many other interesting results - for example, (Not((expr1) And (expr2))) is equivalent to ((expr1) Or (expr2)), and (Not((expr1) Or (expr2))) is equivalent to ((expr1) And (expr2)). If none of this seems to make any sense, don't worry - we'll study these things in more detail in the next tutorial.

The other kind of expression, which normally does NOT have an = sign in it, is the one that is on the other side of the equals sign. For example,

  my_number = some_other_number + 3
In this case, the expression is "some_other_number + 3". The compiler generates the assembly which adds 3 to the variable, which is stored somewhere in memory. Then, the result of this operation is sent to the other variable, the one on the left side of the equation, which of course is also a location in memory. In case you're curious, this is what the assembly looks like:
  ;Copy the value of some_other_number into the processor register eax
  mov eax, dword ptr [ebp-12]
  ;Add 3 to eax
  add eax, 3
  ;Put the result into my_number
  mov dword ptr [ebp-8], eax
Makes you appreciate your nice HLL that you are able to program with, eh? In the early days they didn't have those, and programmers had to program using assembly or machine language! Anyways, the point is that the expression returns a value, which of course must be calculated, unless it's a contant expression, such as "6" which doesn't need to be calculated at all). In the example, the result of the expression is held in eax temporarily until the expression is finished being calculated, then moved off into the variable you wanted it placed in. A much complicated expression, of course, would require even more instructions to calculate, but always the result is the same: a single number is produced and moved into the result variable. With floating point numbers the complication goes up by several orders of magnitude, as the floating point processor must now be involved, but the same thing happens. This is also the case with conditional expressions, except that instead of setting a variable to the result we usually generate two results and check if the results are equal to each other - or not equal. When it's a compound expression, there may be more results. Nevertheless, at the end, just one value is produced - 0 or ...1111 binary.

Of course, it's also possible to use a simpler expression in a conditional, for example

  If my_var Then
  End If
As previously stated, though not emphasized, the conditional will execute so long as the expression is nonzero. In this case the result of the expression is not 0 or ...1111 at all, but whatever the value of my_var is. If my_var is 0, then the condition will not execute. Otherwise it will. This makes it possible to do things like this:
  my_var = my_var - 1
Loop While my_var
This would presumably be more efficient, actually, since less assembly must be generated (since we're not making a comparison with my_var and 0, then making a comparison with the result and 0; instead, we're just making the comparison once).

Making our expressions shorter

One nice thing provided in C is the ability to abbreviate expressions when a variable is on both sides of the expression. For example,

  my_var = my_var - 1
Can be shortened to
  my_var -= 1
And of course the others work as well: +=, *=, /=, etc.

You can also shorten the conditional expression

  If condition Then
    some_var = truth_value
    some_var = false_value
  End If
This is done with IIf:
  some_var = IIf(condition, truth_value, false_value)
This is similar to the use of the ? mark in C. In fact, conditional expressions may themselves be used outside of a conditional block, for example:
  'This is equivalent to printing "0" since 0=1 is never true
  Print Str((0=1))
  'This is equivalent to printing "-1" since 0=0 is always true
  Print Str((0=0))
This can be exploited to simplify some forms of code, though it may make it more difficult to read the code. One odd example I'll give:
  my_var = -((my_var = 0)*my_var)
If you try this out, you see that the ultimate result is setting my_var to itself. That's because if my_var is 0 then the result is 0*0 which is 0; whereas if my_var is anything else, the result is -(-1*my_var), which of course is my_var. More interesting examples can be contrived with little effort.

Closing Up

This has been a bit shorter than the past two tutorials, but I hope I've clarified some points and given you a little more insight into how the compiler works and why things are the way they are. The goal, of course, is that you have as near a complete understanding of these things as you can, but of course I can't be expected to teach you everything. Ultimate understanding would be learning the API of your operating system, assembly language, and how parsing really works. There's no time for that, and it's not very useful anyways. What you have learned will be of some use to you, and hopefully you understand things a bit better than you might if you were studying a "Learn FreeBasic in 24 Days" book. A good understanding of expressions will be extremely important later.

No assignments today, though I strongly recommend you play around with the examples given here, and perhaps come up with some interesting ideas of your own. Some really interesting things can be done with simple expressions, if you think about it.

The seventh tutorial, as I said before, will cover numbers and other such things - how they are stored internally, calculated with, and used.

The seventh tutorial is here

(<--Previous) Back to Index (Next-->)