A Guide to QBASIC for Beginners. By Michael Calkins Floresville, Texas, United States E-mail: "mcalkins0@hotmail.com" Please contact me with any corrections, questions specific to this tutorial, or comments. Post general QBASIC questions on: Jack's QBASIC ("http://www.geocities.com/jacksqbasic/") Updates and revisions of this guide will be posted on Jack's QBASIC thanks to Jack Davies. I tried to make sure the examples in this guide perform as described and that the text is factually accurate. If you find errors, please let me know. I wrote most of it quite late at night. And I have been known to make wildly inaccurate assumtions any time of day. 06-07-2005 PART 1: INTRODUCTION TO CHAPTER 4. (MC-QB-1.TXT) Introduction: The ability to make a machine do what you want is a wonderful and gratifying thing. Computer programming is an enjoyable and fulfilling endeavor. Whether you are wishing to learn for recreational purposes, or perhaps more practical reasons, I congratulate you on your courage, and wish you the best. The skills and knowledge you can attain in the realm of programming can be of help to you with many applications, not all computer related. There are myriads of computer languages. The most primitive, like assembly and machine language can be extremely fast, powerful, and efficient, but are also among the hardest to learn. High-level languages like C++, Java, and BASIC are easier to learn, but are usually not as efficient. BASIC, which stands for Beginners All-purpose Symbolic Instruction Code, is a very old family of high-level languages that dates back decades. As the "Beginners" part implies, BASIC was designed to be simple and easy to learn. As the "All-purpose" part implies, most versions of BASIC are versatile and relatively powerful. The BASIC family includes many dialects, or variants. GW-BASIC and BASICA were among dozens (perhaps an understatement) of old, long obsolete versions. QuickBASIC and QBASIC were newer (but now obsolete) versions meant to be more powerful and versatile. VisualBASIC, a Graphics User Interface based dialect, is now by far the most popular version. It is being used to create myriads of powerful MS-Windows applications. My personal favorite is QBASIC. The QBASIC interpreter is almost universally available since it comes with MS-DOS 5.0 and later, as well as Windows 95 & 98 (you may have to search the CD, but it's there). It is significantly easier to use than some of its predecessors, and, in my opinion, much simpler the VisualBASIC. QBASIC is a stripped down version of QuickBASIC. QuickBASIC, besides being more powerful language-wise, is a compiler. Compilers actually take your code, convert it into machine language, and build it into an executable application. QBASIC, on the other hand, is an interpreter only. It reads the code as it goes, and carries out actions based on the code. As you may have guessed, this has downsides such as these: dependence on the interpreter's presence; the interpreter's environment limits; and, of course, execution speed. Reading and deciphering text instructions is much more time consuming than just doing the actions. Unfortunately, Microsoft QuickBASIC is no longer available on the market. There are other BASIC compilers out there, but I have been disappointed with the ones I have tried. I personally believe QBASIC to be a wonderful language. I will do my best to get you started in it. I assume you already have knowledge of computer usage and algebra. I cannot overemphasize the value of the QBASIC's internal help system. It was the primary tool that I used to learn. True, some aspects of it can be confusing, but it is an extremely useful reference source. It would be an excellent idea for you to refer to the QBASIC Help throughout the course of this discussion. Also, to drive in the ideas, it would be a good idea for you to experiment with your own code as soon as you feel comfortable doing so, especially from chapter 4 on. Examining other people's programs never hurts either. It is not my goal to teach you everything about QBASIC. I don't know everything anyway. My goal is to get you started, by teaching concepts and showing examples. There are many aspects, features, and eccentricies of QBASIC that you will learn on your own. When you are in the QBASIC editor, press SHIFT + F1 for help. Use the ALT button to access the menu system. You can press F1 for context-sensitive help. The chapters are a little large. If you need to, study the chapters in sections. Some chapters deal with multiple subjects. The transitions between subjects make good dividers if you need a break. Each chapter has review questions. These are designed to verify that you understand key concepts. At your discretion, briefly answer them either mentally or orally. Contents: (subject to change) 0. Introduction 1. Binary and hexidecimal number systems. 2. Data, data types, and variables. 3. Expressions, evaluation, and operations. 4. Introdution to screen output, and demonstration of concepts. 5. Variable assignment, and text/number conversion. 6. Introduction to keyboard input. 7. Math functions. 8. Introduction to conditional execution, line numbers, and GOTO. 9. Fancier screen output. 10. Text STRING manipulation part 1. 11. Text STRING manipulation part 2. 12. WHILE and DO loops. 13. FOR loops and more conditional execution. 14. Arrays. 15. SLEEP and INKEY$ 16. User-defined data types. 17. Introduction to file I/O. 18. Introduction to sound. 19. DATE$, TIME$, TIMER, and random numbers. 20. Introduction to graphics. 21. Introduction to sub-routines, and event-trapping. 22. SUB procedures and FUNCTIONs. 23. More graphics. 24. A few words about memory. --- 1. Binary and hexadecimal number systems. We humans all use a base 10, or decimal, counting system. We have 10 numerals (0,1,2,3,4,5,6,7,8,9) and our digital place values are powers of 10. This is natural. Don't we have 10 fingers? Here is how counting systems work. There are a number of numerals equal to the base. Furthermore, each place value is the base to the power of the digit position. The value of any particular digit is obtained by multiplying the numeral by the place value. The number's value is the sum of the values of its digits. Let's see how this works. Base 10 (decimal): digit position: 5 4 3 2 1 0 -1 -2 ----------------------------------------------------------- place value: 100000 10000 1000 100 10 1 .1 .01 Consider the decimal number 3007. Where is the "3"? In the 4th position, which is position 3. What is that position's place value? 10 to the power of 3, ie 1000. So what is the digit's value? 3 times 1000, ie 3000. The same with the "7". The "7" is in the 1st position, which is position 0. The place value is 10 to the power of 0, ie 1. The digit value is 7 times 1, ie 7. 3007 = (3 * (10 ^ 3)) + (0 * (10 ^ 2)) + (0 * (10 ^ 1)) + (7 * (10 ^ 0)) 3007 = (3 * 1000) + (0 * 100) + (0 * 10) + (7 * 1) 3007 = 3000 + 0 + 0 + 7 3007 = 3000 + 7 Counting up in decimal: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, etc. However, digital electronic circuits rely on 2 different states: logic high and logic low, distinguished by different voltage levels. Logic gates can be either closed or open, circuits can be either on or off. All electronic watches, calculators, and computers work this way. Since computers circuits rely on these 2 different states, it is reasonable to assign numeric values to these states. Thus the application of a base 2 counting system. It is as if computers have 2 fingers. In base 2 (binary), there are 2 numerals (0,1), and each place value is a power of 2. Base 2 (binary): digit position: 5 4 3 2 1 0 -1 -2 ----------------------------------------------------------- place value: 32 16 8 4 2 1 .5 .25 Here is an example of a binary number: 100101. Its decimal equivalent is 37. 37 dec = 100101 bin 37 = (1*(2^5)) + (0*(2^4)) + (0*(2^3)) + (1*(2^2)) + (0*(2^1)) + (1*(2^0)) 37 = (1 * 32) + (0 * 16) + (0 * 8) + (1 * 4) + (0 * 2) + (1 * 1) 37 = 32 + 0 + 0 + 4 + 0 + 1 37 = 32 + 4 + 1 Counting up in binary: 0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010, 1011, 1100, 1101, 1110, 1111, 10000, 10001, 10010, 10011, 10100, 10101, 10110, etc. So how would you convert a number into binary? It is actually fairly straight-forward. Find the biggest power of 2 that will fit into the number. The exponent of that power of 2 indicates the digit position to set to "1". Now subtract the digit value, in this case the power of 2, from the number. Repeat the process on the resulting number until the result is 0. For example, let's use 3007. Find the biggest power of 2 that you can subtract from your number (without going negative). In this case 2 to the power of 11, ie 2048, is the biggest. So we know that the 12th digit, that is, digit number 11 will be "1". Now, let's remove what we have already accounted for by subtracting 2048 from 3007 leaving us with 959. Repeat the process. 2 to the power of 9, ie 512, is the biggest power of 2 that will now fit. The 10th digit, that is digit number 9 will be "1". Subtract 512 from 959 leaving 447. Repeat. 2 to the power of 8, ie 256, is the biggest power of 2 that will now fit. The 9th digit, that is digit number 8 will be "1". Subtract 256 from 447 leaving 191. Repeat. 2 to the power of 7, ie 128, is the biggest power of 2 that will now fit. The 8th digit, that is digit number 7 will be "1". Subtract 128 from 191 leaving 63. Repeat. 2 to the power of 5, ie 32, is the biggest power of 2 that will now fit. The 6th digit, that is digit number 5 will be "1". Subtract 32 from 63 leaving 31. Repeat. 2 to the power of 4, ie 16, is the biggest power of 2 that will now fit. The 5th digit, that is digit number 4 will be "1". Subtract 16 from 31 leaving 15. Repeat. 2 to the power of 3, ie 8, is the biggest power of 2 that will now fit. The 4th digit, that is digit number 3 will be "1". Subtract 8 from 15 leaving 7. Repeat. 2 to the power of 2, ie 4, is the biggest power of 2 that will now fit. The 3rd digit, that is digit number 2 will be "1". Subtract 4 from 7 leaving 3. Repeat. 2 to the power of 1, ie 2, is the biggest power of 2 that will now fit. The 2nd digit, that is digit number 1 will be "1". Subtract 2 from 3 leaving 1. Repeat. 2 to the power of 0, ie 1, is the biggest power of 2 that will now fit. The 1st digit, that is digit number 0 will be "1". Subtract 1 form 1 leaving 0. You are finished. So the 12th, 10th, 9th, 8th, 6th, 5th, 4th, 3rd, 2nd, and 1st digits, that is, digits 11, 9, 8, 7, 5, 4, 3, 2, 1, and 0 are all "1". 101110111111 bin = 3007 dec 3007 = (1*(2^11) + (0*(2^10) + (1*(2^9) + (1*(2^8) + (1*(2^7) + (0*(2^6) + (1*(2^5) + (1*(2^4) + (1*(2^3) + (1*(2^2) + (1*(2^1) + (1*(2^0) 3007 = (1*2048) + (0*1024) + (1*512) + (1*256) + (1*128) + (0*64) + (1*32) + (1*16) + (1*8) + (1*4) + (1*2) + (1*1) 3007 = 2048 + 0 + 512 + 256 + 128 + 0 + 32 + 16 + 8 + 4 + 2 + 1 3007 = 2048 + 512 + 256 + 128 + 32 + 16 + 8 + 4 + 2 + 1 Please be sure you understand the concepts so far, or this next section will throw you. The understanding of binary is critical to everything. But binary can be a bit of a handful as you have seen. Isn't there a compromise between binary and decimal? Something that can be easily converted to binary that is also more compact? Yep. It is called hexadecimal, or hex for short, and it is a base 16 counting system. Doesn't adding a third counting system just complicate things? It may to begin with, but you will soon see the wisdom in it. In base 16 (hexadecimal), there are 16 numerals (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F) A=10, B=11, C=12, D=13, E=14, F=15, and each place value is a power of 16. Base 16 (hex): digit position: 4 3 2 1 0 -1 -2 ----------------------------------------------------------- place value: 65536 4096 256 16 1 1/16 1/256 Here is an example of a binary number: 7F. Its decimal equivalent is 127. Its binary equivalent is 1111111. 127 dec = 7F hex 127 = (7 * (16 ^ 1)) + (15 * (16 ^ 0)) 127 = (7 * 16) + (15 * 1) 127 = 112 + 15 Counting up in hex: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 1A, 1B, 1C, 1D, 1E, 1F, 20, 21, 22, 23, 24, 25, 26 Did you notice something about hexadecimal? Its base is itself a power of 2. 16 is 2 to the power of 4, therefore, 1 hexadecimal digit always stores the same amount of information as 4 binary digits. This allows for extremely rapid and easy conversion between hex and binary: hex: binary: - ---- 0 = 0000 1 = 0001 2 = 0010 3 = 0011 4 = 0100 5 = 0101 6 = 0110 7 = 0111 8 = 1000 9 = 1001 A = 1010 B = 1011 C = 1100 D = 1101 E = 1110 F = 1111 Remember our binary 100101 (37 dec)? 0010 0101 2 5 25 hex = 100101 bin Remember our binary 101110111111 bin (3007 dec)? 1011 1011 1111 B B F BBF hex = 101110111111 bin Really, hexadecimal is a way of abbreviating binary into a form easy for humans to read. So how would you convert a number from decimal directly into hexadecimal? It is just like the dec to bin conversion, except for a few things. First, find the biggest power of 16 that will fit into the number. The exponent of that power of 16 indicates the digit position of concern. Here is the main conversion difference: With binary, we didn't ask what to set the digit to; we knew it was "1", since that is the only alternative to "0". But instead of 1 non-zero numeral, we have 15 to choose from. The numeral that we need to use is the result of dividing the number by the power of 16 and ignoring the remainder. Subtract the digit value from the number. Repeat the process on the resulting number until the result is 0. Let us again use 3007 to illustrate. Find the biggest power of 16 that you can fit in your number. In this case 16 to the power of 2, ie 256, is the biggest. We divide 3007 by 256, ignoring the remainder, and end up with 11. So "B" is the numeral for the 3rd digit, that is digit number 2. Subtract the digit value, ie 256 * 11, ie 2816 from 3007, leaving 191. Repeat. Find the biggest power of 16 that you can fit in 191. In this case 16 to the power of 1, ie 16, is the biggest. We divide 191 by 16, ignoring the remainder, and end up with 11. So "B" is the numeral for the 2nd digit, that is digit number 1. Subtract the digit value, ie 16 * 11, ie 176 from 191, leaving 15. Repeat. Find the biggest power of 16 that you will fit in your number. In this case 16 to the power of 0, ie 1, is the biggest. We divide 15 by 1, ignoring the remainder, and end up with 15. So "F" is the numeral for the 1st digit, that is digit number 1. Subtract the digit value, ie 1 * 15, ie 15 from 15, leaving 0. You are finished. So we have again shown that 3007 dec = BBF hex. 3007 = (11 * (16 ^ 2) + (11 * (16 ^ 1) + (15 * (16 ^ 0) 3007 = (11 * 256) + (11 * 16) + (15 * 1) 3007 = 2816 + 191 + 15 Before we go on, understand that it is possible to do both binary and hexadecimal arithmetic on paper. However, a serious problem can develop when you try to do hexadecimal arithmetic yourself. For example try to add "1" hex to "9" hex. Did you say "10" hex? The answer is "A" hex, which is the same as 10 dec. But "10" hex is actually 16 dec. To avoid confusion, it is usually better to avoid manually doing hex arithmetic. Use a calculator or computer, or mentally convert the number first. Before we move on, there are some terms that you need to learn. When used with computers, binary digits are called "bits". 4 bits are called a "nibble". 8 bits are called a "byte". 16 bits are called a "word". 32 bits are called a "double word". Therefore, a nibble is equivalent to 1 hexadecimal digit, and a byte is the same as 2 hexadecimal digits. It is important that you understand this chapter, especially the part about binary. If you need to review, please do so. Review: 1. What are decimal, binary, and hexadecimal? 2. The binary place values are powers of what? How many numerals does binary have? List them. 3. The hexadecimal place values are powers of what? How many numerals does hexadecimal have? List them and their decimal equivalents. 4. 1 hexadecimal digit always corresponds to how many binary digits? Why does this make conversion between the two easy? 5. Briefly explain or demonstrate decimal, binary, and hexadecimal conversion. Hint for the future: If you set the calculator that comes with Windows to "Scientific" mode, it allows very convenient conversion. But do it manually enough that you thoroughly understand the concepts. --- 2. Data, data types, and variables. What is data? It is any value, whether numerical or text that your computer will use. All data stored in computers is ultimately stored as binary numbers. Even text is stored in binary numerical form. Furthermore, all data in computers is stored in some physical location, usually RAM. Text is made up of characters. Since 1 byte (8 bits) is capable of 256 combinations, it is very natural that the IBM Personal Computers use 256 different characters, including all the letters of the alphabet, numerals, punctuation, i/o control characters, and special characters. These characters and their binary representations are universal to IBM PCs. This standard is called ASCII. (Actually, the original ASCII, which is used on other types of computers, defined only 128 characters (0 to 127). Characters 128 to 255 were standardized by IBM.) See the QBASIC Help for a chart of ASCII characters. QBASIC, like other languages, stores and processes data in a very specific, organized manner. Computers are finite objects, and like to work with chunks of data of specific sizes. However, one size does not fit all, and, for various reasons, you will make choices based on your needs. QBASIC provides several data types. A data type is exactly that, a type or category of data. These types can be divided into 2 groups: text and numeric. Each type, with one exception, has a specific length, or size; and with no exception, has specific capabilities. Text: fixed length STRING. variable length STRING. Symbol: $ A STRING holds text, that is, a character or series of characters. "Hello" is an example of a string. "Hello" is 5 characters long, and therefore has a size of 5 bytes. STRINGs can be either fixed length or variable length. We will discuss that later. In either case, though, a string cannot exceed 32767 characters in length. Before I list the numeric data types, we need to discuss something. With your knowledge of binary, you can probably guess how positive whole numbers will be stored. But not all numbers are positive! (Technically, in math, the number 0 is neither positive nor negative, but I will refer to is as positive because you don't put a negative sign in front of it, do you?) How can we express polarity in binary? Suppose that we were to set aside 1 bit in each number, and use it to do this. "1" could indicate negative, whereas "0" could indicate positive. That is the idea behind "signed numbers". Imagine that we use the 16th bit (bit 15) for this purpose. In that case, positive numbers would build from 0 up to 32767. Negative numbers would build up from -32768 to -1 with -1 actually being a greater binary number than -32767. In other words. Inverting bit 15 would not simply invert the polarity. In this case, you would have to either add or subtract 32768 in addition to inverting bit 15. Numeric: signed short INTEGER. Symbol: % signed LONG integer. Symbol: & SINGLE precision floating point. Symbol: ! DOUBLE precision floating point. Symbol: # The INTEGER is the type you will use most often. It is 2 bytes (16 bits) long, allowing 65536 possible combinations. It can store integers, ie whole numbers, in the range of -32768 to 32767. The leftmost bit (bit 15) indicates polarity. 0000 0000 0000 0000 bin = 0 = 0000 hex 0111 1111 1111 1111 bin = 32767 = 7FFF hex 1000 0000 0000 0000 bin = -32768 = 8000 hex 1111 1111 1111 1111 bin = -1 = FFFF hex The LONG integer is 4 bytes (32 bits) long, allowing 4294967296 possible combinations. It can store integers in the range of -2147483648 to 2147483647. The leftmost bit (bit 31) indicates polarity. 0000 0000 0000 0000 0000 0000 0000 0000 bin = 0 = 00000000 hex 0111 1111 1111 1111 1111 1111 1111 1111 bin = 2147483647 = 0FFFFFFF hex 1000 0000 0000 0000 0000 0000 0000 0000 bin = -2147483648 = 80000000 hex 1111 1111 1111 1111 1111 1111 1111 1111 bin = -1 = FFFFFFFF hex But not all numbers are whole numbers; some are mixed numbers. That is where the floating point data types come in. I do not know all the details of how they work, but they use the same principles that scientific notation uses. I imagine certain bits (I don't know which ones) are set aside to keep track of where the decimal point needs to end up. (Or is it a binary point? I really don't know for sure.) This makes for enormous flexibility. These types can be used to store either gigantic numbers or truly infitismal numbers. But there is always a catch, isn't there? The downside is that rounding is part of the deal. Don't be surprised to see numbers rounded to make them fit into the designated space. Of course, digits on the right-hand side of the number will be the ones lost if rounding is needed. Also, I suppose because these numbers are truly binary at heart, the result of mathematical operations will not always be exactly what you expect; miniscule corruption may occur in the right-most digits. For that reason, I do not consider floating point numbers to be 100% reliable. This is only really a problem under certain circumstances though. Very big, or very small floating point numbers are displayed in scientific notation. That is what the "E" is for in some SINGLE numbers, and the "D" in some DOUBLE numbers. The SINGLE precision floating point is 4 bytes (32 bits) long. It can store positive mixed numbers in the range of 2.802597E-45 to 3.402823E+38, and negative mixed numbers in the range of -3.402823E+38 to -2.802597E-45. The DOUBLE precision floating point is 8 bytes (64 bits) long. It can store positive mixed numbers in the range of 4.940656458412465D-324 to 1.79769313486231D+308, and negative mixed numbers in the range of -1.79769313486231D+308 to -4.940656458412465D-324. Some languages allow unsigned types. For example, in C++, an unsigned short integer 2 bytes long could store a number in the range of 0 to 65535. QBASIC provides no unsigned data types. As stated before, any text or number value used in your program must conform to one of these data types. In your program you will sometimes use literal constants. A literal constant is any value written directly into your program. If you were to write the number 180 directly into your program as a value, it would be a constant. String constants are always enclosed in quotation marks. "Hello" is an example of a literal string constant. The quote marks are not part of the string, but they show where it begins and ends. Imagine if your program used only literal constants. It would be very inflexible and rigid. Your program would do exactly the same thing with the same data every time. To use different data, you would have to actually change your program. Fortunately, that is not the case. All programming languages, including BASIC, allow for variables. You remember variables from algebra. Variables always have a value. In QBASIC, that is also true. You can create and use variables. You can assign them values, and reassign them different values as many times as you like. The value you assign to them can be the result of almost whatever you want, including math operations, keyboard input, and file input. In QBASIC, variable names can be up to 40 characters long, and consist of letters and numerals. However, they must begin with a letter. "VarA0" is acceptable, but "0VarA" is not. Names are not case specific. "XPOS" is the same as "xpos". Some languages require you to declare variables using specific commands. You can do that in QBASIC with the DIM statement. However, that is usually optional. Many times, you will just invent a new variable on the spot and use it in your program with no DIM statement. However, variables are always of a specific data type. Which type? It is entirely up to you. Whether you use a DIM statement or not, you can specify a data type. Here is how: With a DIM statement: DIM x AS INTEGER We are creating a new variable named "x" and making it a signed short integer. But remember those symbols in the type list? They are called data type suffixes, and they provide an alternative method. DIM x% This is a different way of doing pretty much the same thing, since the "%" symbol is used for INTEGER. If you do not specify a data type, the variable will be created with the default data type, which is usually SINGLE. However, keep in mind that since each variable has a specific data type, variables with similar names but different data types are actually different variables. "x!" and "x%" are two different variables. Assigning a value to one will not affect the other. In the first example above, "DIM x AS INTEGER", "x" became an INTEGER. So "x" and "x%" are the same and refer to the same variable. But, in the second example, "DIM x%", we are just creating "x%". Since "x" remains undefined, if it is used later, it will be assumed to be a SINGLE. "x" and "x!" would be the same, but "x" and "x%" would be two distinct variables. Be sure you don't get confused as to which variable is of which type. In the following chapters, you will see many examples of both data types and variables. Review: 1. What are data types? Why are they necessary? 2. List the QBASIC data types, and briefly mention the usage and approximate capabilities of each. 3. Which bit in INTEGER indicates polarity? Which bit in LONG? The 4th and 5th questions may be answered together. 4. Consider 1000 0000 0000 0001 binary as an INTEGER. Why is it -32767 and not -1? 5. Consider 1111 1111 1111 1111 binary as an INTEGER. Why is it -1 and not -32767? 6. Which two data types are capable of storing the number 3.1415? 7. What is a literal constant? 8. What is a variable? 9. Do you always need a DIM statement just to create a variable? 10. Briefly, what is a data type suffix, and what does it do? 11. Must all data in your program conform to a data type of some form? --- 3. Expressions, evaluation, and operations. What is an expression? It is anything that can be evaluated as having a value, whether numeric or text. QBASIC is an extremely flexible language, and the open nature of expressions has a lot to do with it. Expressions can be made in a seemingly infinite number of combinations. They can consist of constants, variables, the results of operations, and function outputs. For example: A constant can be an expression. 3 So can a variable: x% So can a combination with operators: 5 + 2 - 1 or 5 + x% - y% Get the picture? "3" will be evaluated to 3. "x%" will be evaluated to whatever "x%"'s value is. "5 + 2 - 1" will be evaluated to 6. "5 + x% - y%"'s evaluation depends on the values of the variables. All expressions, by neccessity, have specific values. What will you use expressions for? Anything that requires a value. When you assign a value to a variable, or when you pass values to a function, or when you use values as parameters for anything, you will be using expressions. (There are a few instances in QBASIC where parameters will not be expressions, but that is not important now.) Now would be a good time to list the operators and describe what they do. Arithmetic operators: + Addition. When used with numbers, this operator adds the two numbers together. 5 + 2 is 7. When used with text strings, it combines them "abcd" + "efg" is "abcdefg". - Subtraction. 5 - 2 is 3. * Multiplication. 5 * 2 is 10. / Division. 5 / 2 is 2.5. \ Integer division. This is like division, but the remainder is ignored. 5 \ 2 is 2. This operator is a counterpart of MOD. MOD Modulus. This finds the remainder of a division. 5 MOD 2 is 1 because 5 divided by 2 is 2, remainder 1. This operator is a counterpart of integer division. ^ Exponentiation. This is used to raise a number to a power. 5 ^ 2 is 25. Boolean Algebraic operators. These perform bit-wise logic operations on INTEGERs and LONG integers. They are bit-wise in that they deal with each bit individually, with "1" being "on" or "true", and "0" being "off" or "false". AND, OR, XOR, EQV, and IMP are dual-operand, ie they have 2 inputs. NOT is single-operand with only 1 input. AND Boolean AND. Performs a bit-wise logic AND. 5 AND 2 is 0. Why? look at the binary equivalents: 5 is 0101 binary. 2 is 0010 binary. Ask yourself which bits that are set to "1" do those two binary numbers have in common? They have none in common, so the result is 0. If we used 15 AND 68, then the result is 4. 0000 1111 binary AND 0100 0100 binary have 0000 0100 binary "on" bits in common. 0000 0100 binary is 4. What AND does is it finds out which bits are on ("1") in both the first number AND the second number. The AND operator is an excellent way for testing to see which bits in an INTEGER or a LONG are set to "1", which is another way of saying that it is good for isolating parts of numbers. With each bit: true AND true is true false AND false is false true AND false is false false AND true is false OR Boolean inclusive OR. Performs a bit-wise logic OR. What OR does is it finds out which bits are on ("1") in either the first number OR the second number. 5 OR 2 is 7. In binary that is 0101 bin OR 0010 bin is 0111 bin. 15 OR 68 is 79. 0000 1111 bin OR 0100 0100 bin is 0100 1111 bin. The OR operator is an excellent way of forcing certain bits to "1". With each bit: true OR true is true false OR false is false true OR false is true false OR true is true XOR Boolean eXclusive OR. Performs a bitwise logic XOR. What XOR does is it finds out which bits are unequal in two numbers. 5 XOR 2 is 7 because 0101 bin XOR 0010 bin is 0111 bin, that is, the first through the third bits are unequal. 15 XOR 68 is 75 because 0000 1111 bin XOR 0100 0100 bin is 0100 1011 bin, that is, the first, second, fourth, and seventh bits are unequal. The XOR operator is an excellent way of inverting specific bits. With each bit: true XOR true is false false XOR false is false true XOR false is true false XOR true is true EQV Boolean EQuiValence. Tests for bit-wise equivalence. It is the exact opposite of XOR. Whichever bits are equal are set to "1". 5 EQV 2 is -8 because 0000 0000 0000 0101 bin EQV 0000 0000 0000 0010 bin is 1111 1111 1111 1000 bin, that is the 4th through the 16th bits are equal. The result is the exact opposite of XOR. 15 EQV 68 is -74 because 0000 0000 0000 1111 bin EQV 0000 0000 0100 0100 bin is 1111 1111 1011 0100, that is, the 3rd, 5th, 6th, and 7th thru 16th bits are equal. With each bit: true EQV true is true false EQV false is true true EQV false is false false EQV true is false IMP Boolean IMPlication. I am not terribly sure what this is for. I never use it. 5 IMP 2 is -6. 0000 0000 0000 0101 bin IMP 0000 0000 0000 0010 bin is 1111 1111 1111 1010. I believe that this is the only dual-operand Boolean operator that is not associative, ie, a% IMP b% doesn't always equal b% IMP a%. With each bit: true IMP true is true false IMP false is true true IMP false is false false IMP true is true NOT Boolean NOT. Performs a bit-wise logic inversion. This is a single operand operator. All "0"s become "1"s, all "1"s become "0"s. True becomes false, false becomes true. NOT 5 is -6, that is, 0000 0000 0000 0101 when inverted becomes 1111 1111 1111 1010. NOT 2 is -3. NOT 15 is -16. NOT 68 is -69. Of course, NOT 0 is -1, and NOT -1 is 0. With each bit: NOT true is false NOT false is true By now, you must have noticed my use of the phrases "true" and "false". They are extremely important phrases in algebra, computer programming, and electronic circuit design. With algebraic equations, an equation is true whenever it works, whenever it makes sense, whenever it follows the rules and laws of math. An equation is false whenever it doesn't work, doesn't make sense, that is, whenever it doesn't follow the rules and laws of math. For example: you know that 2 + 3 = 5 is true, ie, it is correct. You also know that 10 + 7 = 1 is false, that is, it is incorrect. Any equation or inequality must be either true or false. That principal is used heavily in QBASIC and other languages. In computers we can take this a step further. With binary numbers, if any bit is set to "1", we will consider it to be "on" and "true". If any bit is set to "0", we will consider it to be "off" and "false". You should have already observed this with the Boolean operators. (Please note that when you use Boolean operators, the operands are converted to either INTEGERs or LONGs, if they are not already, for the sake of the operation.) The previous paragraph discussed truth and falsehood at the bit level. What about complete numbers? 0, as a complete number, will be considered by QBASIC's condition-dependant commands (such as IF and WHILE) to be false. Those same commands consider any number other than 0 to be true, because every non-zero number has at least one bit set to "1", or true. However, "true" can be idealized as -1, that is, all bits set to "1". For that exact reason, using -1 to symbolize "true" is ideal for use with Boolean operators. That is why you will see QBASIC's Help, and sample programs associate "true" with -1. Since all bits are "on" or "true", the number can be described as being entirely "true". Relational operators. Can be used with either numbers or text strings. = Equality. This operator test for equality, either between two numbers, or between two text strings. 5 = 5 is true. 17 = 1 is false. "abc" = "abc" is true. "abc" = "ABC" is false. < Less than. 10 < 20 is true. 20 < 10 is false. 15 < 15 is false. > Greater than. 20 > 10 is true. 10 > 20 is false. 15 > 15 is false. <= Less than or equal to. 10 <= 20 is true. 20 <= 10 is false. 15 <= 15 is true. >= Greater than or equal to. 20 >= 10 is true. 10 >= 20 is false. 15 >= 15 is true. <> Greater or less than, but not equal to. Basically, an inequality tester. 10 <> 20 is true. 20 <> 10 is true. 15 <> 15 is false. "abc" <> "abc" is false. "abc" <> "ABC" is true. Parentheses: () Parentheses enclose anything that should be treated as an entity, and given priority. Items enclosed in parentheses are evaluated before items not included. 5 + 2 * 3 is 11. (5 + 2) * 3 is 21. QBASIC has a set order of operations (for details, search the Help), but since I get confused, I use parentheses heavily, sometimes just to be on the safe side. You will find that more than one tough bug will result from nothing more than confusion over the order of operations. Ultimately, all numeric expressions are either true (non-zero) or false (zero). This is especially important when you use condition-dependant statements like IF, CASE, WHILE, DO WHILE, DO UNTIL, and FOR, all of which test for truth. Also, in the actual code, you will indicate a number is hexadecimal by including an ampersand and an h before it. &hC is 12, &hFF is 255, &h80 is 128. This also applies to STRINGs that you convert to numbers (You will learn how soon). Review: 1. What are expressions? 2. For what can expressions be used? 3. Briefly list the arithmetic operators. 4. What do all Boolean operators have in common? What data types do they operate on? 5. List the Boolean operators and briefly explain each. 6. Briefly explain truth and falsehood as it applies to bits. 7. With regard to complete numbers (not just one bit), are all non-zero numbers true? 8. With regard to complete numbers (not just one bit), why is -1 the preferred symbol of complete truth? 9. Briefly explain truth and falsehood as it applies to the relational operators. 10. How do you indicate hexadecimal numbers in the code itself? --- 4. Introduction to screen output, and demonstration of concepts. So far, I have been explaining concepts. It will soon be time to demonstrate some of them. This may be an important step for you, as it will transform what I have taught in the last 3 chapters from abstract into practical. By the time you finish with this chapter, you will probably be capable of writing your own simple programs. That step will be essential for you, since just reading about something is not as good as doing it and gaining experience. All programs in any language have flow. What is flow? It is the manner and order in which instructions are acted upon. Really, it wouldn't make sense for all the lines in your code to execute at the same time. Execution is pretty much sequential. That means that, ordinarily, each command is executed after the one preceding it is completed. In this way, the program is orderly, and the flow is smooth. Of course there are jumps, conditional jumps, and code blocks, all of which will be discussed later. Before we get too far, I need to mention something. You can insert comments into your code. These comments are not really part of the code, but are ignored by the interpreter (with 2 minor exceptions). REM can be used to accomplish this, but a much better way is to use the single-quote character ('). Whenever you see the single-quote character in a program, and it is not contained within quotation marks as part of a STRING constant, then it is a marker for either a comment or a meta-command. QBASIC only uses two meta- commands: '$STATIC, and '$DYNAMIC. Neither are of any concern to us right now. That is what I meant by 2 minor exceptions. I will use comments heavily to show you what specific lines in the code are for. In your own programs, it is a good idea for you to use comments to keep yourself from getting confused, to organize yourself, to remember your train of thought, and to aid other programmers in understanding your code. But how will you know what your program is doing? Most programs have an interface, or method of communicating with the user. Usually the screen is used for output, and the keyboard is used for input. You will be introduced to keyboard input in the next chapter, but for now we will change our program's data by just modifying the code itself. You probably know what the screen is. It is the monitor, the display, that you are looking at right now. Most are close relatives of the television screen, with electron guns energizing pixels (dots of phosphor) and making them glow red, green, and blue with varying brightness. How is the screen controlled? By electronic circuits within the monitor itself. They get their information through a cable attached to your computer's graphics adapter. It is the graphics adapter (usually a VGA card) that keeps track of, formats, and processes screen output. The graphics adapter is an vital part of the computer itself, and is controlled as hardware. The processor can instruct the graphics adapter what to do. This is usually accomplished through sections of BIOS or operating system code. I would be lying to you if I told you I knew exactly how QBASIC manages screen output. It could use either the DOS or BIOS methods, or it could write to the section of RAM used by the graphics adapter. I can guess, but I don't know for sure. The original methods for accessing the screen were actually based on methods used for devices that weren't screens at all. From what I read, some of the early computer output was very similar to teletype machines. Some of the instructions are what you might expect for a printer. This method is called the console method. The device "CON", console, is opened the same way you would open a file. Text is sent, with certain characters symbolizing certain actions, such as line feed, carriage return, and start new page. In QBASIC, you can do this, but it is not the preferred way. However, because old habits die hard, even the preferred QBASIC text output resembles the console method. There is such a thing as a cursor. This is used to show where the next text output will begin. Later, (not neccessarily from me), you will learn how to hide it, unhide it, relocate it, and change its shape. For now, just know that it exists. The screen, as far as text is concerned, is divided into a grid of horizontal lines and vertical columns. Each character of text occupies exactly 1 block of this grid. QBASIC uses a text viewport. It is an are of the screen that QBASIC uses for sequential text output. It is usually from lines 1 to 24. You will learn how to resize it later. Text is displayed on the screen sequentially, with the cursor keeping track of where the next output will occur. The screen is so many columns wide, usually 80. Output that runs past the end of the line is simply continued on the next line. (Of course, you can decide to start on new lines arbitrarily.) The screen can also scroll when text ouput runs past the bottom of the text viewport. That way, screen output can be endless; you can just keep writing, and writing, and writing. In QBASIC, you use the CLS statement to clear the screen. See the QBASIC Help for details. Usually, you don't need parameters with this statement. CLS 'clears the screen That line, when executed, will clear the screen, and restore the cursor to the top left corner. But now that the screen is clear, how can we write text to it? In QBASIC, the best way is with the PRINT statement. A glance into QBASIC's help will reveal that the PRINT statement is complex and versatile; it can be used for screen output, and also file/device output. However, the initial explanation of PRINT need not be that complex. PRINT is a statement that can take multiple parameters. PRINT by itself with no parameters just skips a line on the screen, ie, moves the cursor down 1 line. Usually, though, you will use print with at least 1 parameter. You can use expressions, either STRING or numeric, as parameters for PRINT, the values of which will be outputted to the screen. You can even use more than 1 expression on the same PRINT statement. In such a cases, expressions in the expression list are separated by either commas, or semicolons. See the Help for details. We will use the semicolon much more often than the comma. When the semi-colon is used, it keeps the cursor where it ends up after the expression is displayed. The next screen output will start where the previous output left off. When PRINT is done, it usually moves the cursor to the beginning of the next line. However, this can be prevented by using a semicolon after the last expression. CLS PRINT "Hello world!" '1 expression, a literal string 'constant, for display. The cursor is 'then moved to the next line. Screen output: Hello World! Here's another example: CLS PRINT "The cube root of 125 is:"; 125 ^ (1 / 3) '2 expressions, a string constant, and 'the result of math operations. A 'semicolon separates the 2 'expressions. Screen output: The cube root of 125 is: 5 So now that you know how to get screen output, you can experiment with and and observe the results of most of the concepts we have taught so far. Example: CLS PRINT "Arithmetic demonstration:" PRINT "10 will go into 53 this many times:"; 53 \ 10 PRINT "with "; 53 MOD 10; "left over." PRINT PRINT "Boolean demonstration:" PRINT "-1 AND 32 is"; -1 AND 32 PRINT "-1 AND 64 is"; -1 AND 64 PRINT "-1 AND 128 is"; -1 AND 128 PRINT "64 AND 32 is"; 64 AND 32 PRINT "64 AND 64 is"; 64 AND 64 PRINT "64 AND 128 is"; 64 AND 128 PRINT "NOT 0 is"; NOT 0 PRINT "NOT -1 is"; NOT -1 PRINT PRINT "3 different ways of doing the same thing:" PRINT "abc" + "def" + "ghi" 'splice STRINGs PRINT "abc"; "def"; "ghi" 'print 3 STRINGs PRINT "abc"; 'stay on same line PRINT "def"; 'stay on same line PRINT "ghi" Screen output: Arithmetic demonstration: 10 will go into 53 this many times: 5 with 3 left over. Boolean demonstration: -1 AND 32 is 32 -1 AND 64 is 64 -1 AND 128 is 128 64 AND 32 is 0 64 AND 64 is 64 64 AND 128 is 0 NOT 0 is -1 NOT -1 is 0 3 different ways of doing the same thing: abcdefghi abcdefghi abcdefghi Another example: CLS PRINT "Hexadecimal demonstration:" PRINT &h0; &hF PRINT &h10; &h1F PRINT &h20; &h2F PRINT &h30; &h3F PRINT &h40; &h4F PRINT &h50; &h5F PRINT &h60; &h6F PRINT &h70; &h7F PRINT &h80; &h8F PRINT &h90; &h9F PRINT &hA0; &hAF PRINT &hB0; &hBF PRINT &hC0; &hCF PRINT &hD0; &hDF PRINT &hE0; &hEF PRINT &hF0; &hFF Screen output: Hexadecimal demonstration: 0 15 16 31 32 47 48 63 64 79 80 95 96 111 112 127 128 143 144 159 160 175 176 191 192 207 208 223 224 239 240 255 Now would be a good time for you to open up QBASIC and hammer out a few experimental lines of code. Press SHIFT + F1 for help, F1 for context-specific help, and SHIFT + F5 to run. (F5 runs a program or resumes an interrupted program.) Use the ALT button to access the menu system. Review: 1. Briefly explain what you know so far of program flow. 2. What are comments? Why are they useful? How do you insert them? 3. What statement (command) can you use to clear the screen? 4. What is the best statement you can use to display text on the screen? 5. Can you use more than 1 expression for screen output on a PRINT statement? If so, how can you separate expressions? 6. What key combination can you press to access the Help in QBASIC? CONTINUED IN "MC-QB-2.TXT"