From PBasic to CGetting a compilerOne thing about PBasic is that we all had a compiler and an Integrated Development Environment (IDE) that was standard across all of our teams. In C there are many different IDEs and compilers out on the Internet to choose from. When the new Robot Controller is introduced I think there will be a standard compiler and IDE we will use. However before we know this we can start with one of the other compilers on the Internet. A place to get a compiler from.The place to get a complier will impress many mentors who learned to program in the mid to late 80 s. It s the Antique Software Page from Borland. Borland had a compiler called Turbo C. We can find this on this page here: http://community.borland.com/article/0,1410,20841,00.html. Download the zip file and unzip it. We will end up with three directories, Disk 1, Disk 2, and Disk 3. Take the contents of Disk 2 and 3 and then copy them into the Disk 1 folder. Once all of the files are in Disk 1, run INSTALL.EXE. We will get an old DOS based installer, follow the steps to install this package. The source drive is the drive we have unzipped the file on. The Source path should point at the DISK1 directory. Install it to a hard drive. Once the package has been installed we need to do a test compile, copy the program below into a file on the hard drive, in this example we have called this file HELLOWRD.C. This file has to be fewer than 8 letters long and should end with the .C extension. En example of this file name would be Hellowrd.C. Now start a command line or DOS Box. The first thing in the DOS box we will need to do is to set the path. Type in the following line, substituting the path to the TC directory for the one here: PATH=E:\TC Use the drive name and cd command to move around in the DOS box to the directory where we have placed the Hello World file in. The author os this page has placed example code in the E:\JimsCode\C\Test directory. An example of getting to this directory would be: E: CD JIMSCODE CD C CD TEST The first E: will move us to the E: drive, the next CD commands will point us to the E:\JimsCode\C\Test directory. Once in this directory we should be able to type TCC HELLOWRD.C and receive this output: E:\JimsCode\C\Test>TCC HELLOWRD.C Turbo C Version 2.01 Copyright (c) 1987, 1988 Borland International hellowrd.c: Turbo Link Version 2.0 Copyright (c) 1987, 1988 Borland International Available memory 396834
TCC is the Turbo C command line compiler. There is a simple DOS bassed IDE if we use TC, we will not talk about this. Once the compile happens we should have a HELLOWRD.EXE file in our directory. If we run it we will get: Hello World Our First Program#include int main(void) { printf("Hello World\n"); return 0;} Let s look at this program line by line. The first line #include The int main(void) line is a declaration of a function. The first item is the return type of the function, int is an integer from 32,768 to 32,767. The next part of the line tells us what the name of the function is. main is the name of the function that begins every C program. The next part of this line tells us what items we are going to pass into the function. void means we will not be passing anything into it. The next line is the open block symbol {. This means that a block of code will follow. The block will end at the closing } symbol. The line that is going to do everything that this program does is this one printf("Hello World\n");. It is a call to another function called printf. This other function is declared in the stdio.h library, so we don t see the body of it. The item that follows is a string. The string begins and ends with double quote marks " ". The text in the string up until the \n is what is going to be displayed to the console. The \n is the new line symbol. The last line of the main function is return 0;. It returns a 0 to the calling function. Since this is main we will be passing the 0 to the operating system. Notice that the two lines in the block end with the semicolon ;. This tells C the line is finished start a new line. In PBasic we would have just started a new line, however in C we could if we wanted to written both of the lines on one line like this: printf("Hello World\n"); return 0;
This however is bad form and should not be used. What this program does is that it displays the text Hello World to the console. It is the same program as this in PBasic: '{$STAMP BS2sx}Debug "Hello World", cr One important item to mention is that C is a case sensitive language. This means that a variable names MyVar is different from a variable called myvar. Pbasic was not a case sensitive language. Basic Data TypesIn PBasic there were two basic types: BYTE which was used for numbers from 0 to 255 WORD which was 0 to 65,536 In C there are quite a few more types, the integer types are: char which is 128 to 127int which (on most systems) is 32,768 to 32,767 long which (on most systems) is 2,147,483,648 to 2,147,483,647
When we say on most systems, int and long are compiler independent, which means some compilers and processors will treat int as a 16 bit integer (from 32,768 to 32,767) while others might treat int the same as long. If we don t want to use negative numbers we can place a unsigned label in front of the numbers and we will get: unsigned char which will now be 0 to 255 (like BYTE above)unsigned int which will now be 0 to 65,536 (like WORD)unsigned long which will be 0 to 4,294,967,296
For floating point math we have: float which will get us as much floating point math as we needdouble which is twice the size of float
Declaring a variable is different in C than PBasic. In PBasic we would use: MyVar var byte
The name of the variable is first on the line, followed by var then the type we want. In C we start with the type and then follow it with the name of the variable, followed by the semi colon. int MyVar;
The mathematical operations in C are the same as PBasic (with the addition of the semicolon at the end of the line). In PBasic to assign 32 to the variable MyVar we would use: MyVar = 32 In C: MyVar = 32; To add, subtract, multiply and divide MyVar and 4 and store the result in MyVar2 we would use for PBasic: MyVar2 = MyVar + 4 MyVar2 = MyVar 4 MyVar2 = MyVar * 4 MyVar2 = MyVar / 4 To do the same functions in C we would use the same lines: MyVar2 = MyVar + 4; MyVar2 = MyVar 4; MyVar2 = MyVar * 4; MyVar2 = MyVar / 4; To do the same things as above but to put the result back in the variable MyVar we would use in PBasic: MyVar = MyVar + 4 MyVar = MyVar 4 MyVar = MyVar * 4 MyVar = MyVar / 4 We could use the same lines in C, but C gives us a short cut, we can use the +=, -=, *=, and the /= operators like this: MyVar += 4; MyVar -= 4; MyVar *= 4; MyVar /= 4; In fact we can shorten += and -= up even further if we are only going up and down by one. MyVar++; is equivalent to MyVar = MyVar + 1 in PBasic.MyVar--; is the same as MyVar = MyVar 1.
We can also use the parentheses like in PBasic to keep the math working right. 4*5+4 is different than 4*(5+4). Let us use the following program to explore the integer variables and math operators: #include int main(void) { char number=0; while(1) { printf("%d ",number); number++; }} Try different types in the line char number=0;. We can also try different math symbols in the number++; line. To play around with the different floating point number types let us try the following program, this program might give us a compiler warning about line 5, lets ignore that warning for now. #include int main(void) { float number=0.0; while(1) { printf("%f ",number); number+= .01; }} Again try different things in lines 5 and 10. printfWe are using a function called printf to display numbers, this would be a good time to talk a little bit about this function. This function has two parts, the formatting part, and the values part. The formatting part is in a string. This string can be composed of text and some sort of formatting operators. These formatting operators can start with a percent sign (%) or a slash (\). The slash (\) places a control character into the string. The common control characters are \n for a new line, \t for a tab, and \\ for a slash (\). The percent sign (%) tells the formatter to insert a number at this point in the string. A %d is for a decimal number, and a %f is a floating point number. These % number will tell the printf function to get the number from the second part of the function. Each % field in the format section will take a number from the number list and insert it into the string. An example of this is: printf("%d %d %d %f %d\n",12, 15, 17, 14.5, 125);
The printf function will find the first %d and then look at the number list and find the 12 should be placed into the first %d, the second %d will grab the 15, the third will take the 17. Then the printf function runs into a %f and it will find the 14.5 in the list. This is because the first three % have taken the first three numbers. The final %d takes the last number on the list of the 125. The output of this will be: 12 15 17 14.500000 125 We can use some more formatting in the % fields as well. To reserve a set number of spaces for a number add the number of spaces that the number will take up between the % and the formatting character (d or f). This is useful for a table of numbers where we want the numbers to line up. An example is: printf("%d %3d %d %f %d\n",12, 5, 17, 14.5, 125);printf("%d %3d %d %f %d\n",12, 15, 17, 14.25, 12);printf("%d %3d %d %f %d\n",12, 115, 17, 14.0, 25);
The output will be: 12 5 17 14.500000 12512 15 17 14.250000 1212 115 17 14.000000 25 Notice how the second column of numbers lines up. The floating point still looks a little bit odd. If we want only want two numbers after the decimal point we can use the formatting for this as well. Between the % and the f we will place a .2 . Example: printf("%d %3d %d %.2f %d\n",12, 5, 17, 14.5, 125); printf("%d %3d %d %.2f %d\n",12, 15, 17, 14.25, 12); printf("%d %3d %d %.2f %d\n",12, 115, 17, 14.0, 25);
The output will be: 12 5 17 14.50 12512 15 17 14.25 1212 115 17 14.00 25 To pad the number with left zeros we will add a leading 0 to the number of places we want to display. Example: printf("%d %3d %d %.2f %03d\n",12, 5, 17, 14.5, 125); printf("%d %3d %d %.2f %03d\n",12, 15, 17, 14.25, 12); printf("%d %3d %d %.2f %03d\n",12, 115, 17, 14.0, 25);
The output will be: 12 5 17 14.50 12512 15 17 14.25 01212 115 17 14.00 025 To left justify numbers add a between the % and the formatting number, an example: printf("%d %-3d %d %.2f %03d\n",12, 5, 17, 14.5, 125); printf("%d %-3d %d %.2f %03d\n",12, 15, 17, 14.25, 12); printf("%d %-3d %d %.2f %03d\n",12, 115, 17, 14.0, 25);
The output will be: 12 5 17 14.50 12512 15 17 14.25 01212 115 17 14.00 025 Aliases and Bit FieldsAliases in PBasic are defined like this: MyVar var byteMyVar2 var MyVar If we changed the value of MyVar the variable MyVar2 would also be changed. C does not have a formal way of declaring aliases and doing this. Bit Fields in PBasic are defined very much like aliases: MyVar var byte MyBit0 var MyVar.bit0 C also has no way of defining parts of a already declared variable. There is a way of declaring bits from a variable, however it is complicated and it will slow down our code. The methods of accessing bits from a variable the we are going to use are the bitwise operators. For the bitwise operators we are going to review a little Boolean logic. From PBasic we should know that a byte is composed of 8 bits. A word is 16 bits. A bit is 0 or 1. Boolean logic combines the bits in many ways. In good ol base 10 we have four basic operators, Addition (+), Subtraction (-), Multiplication (*), and Division (/). In Boolean logic we had three basic operators, And (&), Or (|), and Not (^). We can express these operators using logic tables: And: Or: Not: A B | Output A B | Output A | Output 0 0 | 0 0 0 | 0 0 | 1 0 1 | 0 0 1 | 1 1 | 0 1 0 | 0 1 0 | 1 1 1 | 1 1 1 | 1 In other words if we had a bit A which is 1 and a bit B which is 0 and we used the Or (|) operator on them we look at the Or table find the 1 0 row and look at the output from it which is 1. Since we can not get to the bits easily in a byte, we have to perform these operations on byte level. In order use these operators on a byte level we will have to look at number in different bases. We think in base ten or what we are going to call decimal. The right most digit in a base ten number is the ones digit. The next number to the left is the tens, the next one is the hundreds and so on. To express this another way the number 143 is 1 in the hundreds place, 4 in the tens place and 3 in the ones place or (1*100)+(4*10)+(3*1). We are going to use two other bases, base 2 which we call binary, and base 16 which we call hexadecimal. In binary we have the ones place, the twos place, the fours place, the eights place, and so on. So the number 1011, breaks down like this. 1 in the eights place, 0 in the fours place, 1 in the twos place, and 1 in the ones place. In decimal we will add the places up (1*8)+(0*4)+(1*2)+(1*1) = 11. The other base we use is hexadecimal. The places here are the ones, the sixteens, the 256s, and the 65536s. For this numbering system we will use the numbers form 0 to 9 and then the letters from A to F which represents the number from 10 to 15. So the number 5E is broken down like this, 5 in the sixteens place and E (or 14) in the ones place. In decimal we will add up the places (5*16)+(14*1) = 94. Converting between hexadecimal to binary is very easy if we use this chart: Hex Bin Hex Bin Hex Bin Hex Bin 0 0000 4 0100 8 1000 C 1100 1 0001 5 0101 9 1001 D 1101 2 0010 6 0110 A 1010 E 1110 3 0011 7 0111 B 1011 F 1111 Converting 5E to binary is as easy as looking up the binary sequence for 5 which is 0101 and looking up the binary sequence for E which is 1110 and then combine them like this 01011110. To convert between binary or hexadecimal and decimal, we use a calculator. Trust the author of this document, using a calculator is the quickest way to convert. If we turn the scientific mode of the Microsoft Calculator on, we can convert very easily. Now getting back to binary logic. If we had two bytes we can now use binary operations on them. If we had a byte which is 54 and a byte which is 125 we can Or (|) them together to get a result. 54 is 36 in hex or 00110110 in bin,125 is 7D in hex or 01111101 in bin,Oring the bits gives us 01111111 in bin or 7F or 127. 54 is 36 in hex or 00110110 in bin,125 is 7D in hex or 01111101 in bin,Anding the bits is 00110100 in bin or 34 or 52. In C we represent hex numbers with a 0x in front of the number 5E would be 0x5E, it can also be 0x5e. Programmers do not use binary notation in C, in fact the author of this document does not know how to represent a binary number in C. A warning however, there is another base called octal. These numbers begin with a leading 0. Octal is base 8 so there is no 8 or 9 in an octal number. Many young C programmers fall into the trap of lining up numbers with leading zeros not realizing that this converts the number to octal. So never start a number with a leading 0. We can use these operators to find or set bits in a number. If we read a value of 56 from some input port and we needed to know what the 5th bit is, we can use the And (&) operator and a bit mask to find out. The bit mask we will use is 00010000(bin) 10(hex) since we need to know about the fifth bit, this is the only bit one. We will then And it with the number to find out if the bit is set: 56(dec) is 38(hex) or 00111000(bin) Anding 00010000(bin) Gives us 00010000(bin)
Notice that the if the fifth bit is set we will get the bit mask out of the function, if the bit is not set we will get 0. The C code for this looks like this: int number = 56; if((number&0x10)==0x10) { printf("The fifth bit is on\n");} else { printf("The fifth bit is off\n");} To set a bit we will use the Or (|) operator. To set the second bit in a field the C code will look like this: int number = 56; printf("Number=%d (0x%x)\n",number,number); number = number | 0x02; printf("Number=%d (0x%x)\n",number,number);
Notice we have a new printf number format, %x. %x will display the number as a hexadecimal number. %x will display all of the numbers between A and F in lowercase. The %X will display them in uppercase. To clear a bit we will need the bit mask to be the 2s complement of the bit we want to clear. If we are clearing the 5th bit the mask will be 11101111 or 0xEF. We can build this mask two ways. We can use 0xEF or we can use ~10. Remember that Not (~) reverses every bit. Once we have the mask we use the And (&) operator on the number. An example: int number = 56; printf("Number=%d (0x%x)\n",number,number); number = number & 0xEF; printf("Number=%d (0x%x)\n",number,number);
Or int number = 56; printf("Number=%d (0x%x)\n",number,number); number = number & (~0x10); printf("Number=%d (0x%x)\n",number,number);
Parentheses are used in this example to point out which operation will happen first. Parentheses are also a good idea in case another programmer has to modify our program, they will have a easier time to figure out what we wanted to do. ConstantsC has a very good method for declaring constants. In PBasic we use the CON keyword, to declare a constant in C use the #define keyword but in a different order trhan PBasic which look like this: c_p1_y CON 1
In C we use this: #define c_p1_y 1 Notice there isn t an equal sign (=) nor is there a semi-colon (;) at the end. This is because everything that follows the label is used as the constant. An example is: #define MAX_SPEED 255 #define MIN_SPEED 0 #define MIDDLE_SPEED (MAX_SPEED + MIN_SPEED) / 2 Constants in C can be declared using other constants. If we did the math from above and used these defines: #define MAX_SPEED 255 #define MIN_SPEED 0 #define MIDDLE_SPEED 127.5 If we changed the MIN_SPEED to 10. Then we would have to change MIDDLE_SPEED as well. However if we used the MIDDLE_SPEED (MAX_SPEED + MIN_SPEED) / 2, we would not have to change this line. #defines don t have to be numeric either. If we have a printf format string that we use everywhere and we may have to change it we can put it into a #define and only change the #define. Example: #define TABLE_FORMAT "%3d %5d %4d\n" if then else statementThe first statements in C will look at are the if then else statements. In PBasic these statements look like this: if user_display_mode = 0 then Out8 = 0 Out9 = 1Else Out8 = 1 Out9 = 0Endif In C these statements look like this: if(user_display_mode == 0) { Out8 = 0; Out9 = 1;} else { Out8 = 1; Out9 = 0;} Notice the then is removed from the if statement. In C the parentheses take the place of the then statement. The parentheses encapsulate the logic we want to check. The endif is also removed. It is replaced with the curly brackets, the start and end curly brackets define a program block of code. The one thing is that is kept the same is the else. One thing that most programmers really get wrong is the equal sign. Notice it is a double equal sign ==. This is the comparison equal sign. The single equal sign is always used in assignment. C allows us to assign things in the if statement, so if we accidentally wrote user_display_mode = 0, C would both assign the variable user_display_mode the value 0 and causes the if statement to be true. In order to remember that the equals has to be a double equals C programs have adopted a standard of writing the if statement in the opposite order: if(0 == user_display_mode) If we forget the double == sign the compiler will give us an error because we cannot assign 0 the value of user_display_mode. We don t need to code the else block if we don t need it. The example would look like this: if(0 == user_display_mode) { Out8 = 0; Out9 = 1;} We can use other comparisons in the place of equals. For not equals the symbol is (!=) for greater than (>), less than (<), greater than or equal to (>=) and less than or equal to (<=). For Next LoopThe PBasic for loop looks like this: for MyVar = 1 to 100 debug "MyVar=", dec5 MyVar, crnext In C the for loop looks like this: for(MyVar=1;MyVar<101;MyVar++) { printf("MyVar=%5d\n",MyVar); } ><101;MyVar++){ printf( MyVar=%5d\n ,MyVar);} The for loop is broken into three parts, each separated by a semicolon (;). The first part of the loop is the assignment part. This is where the variable is set to the initial value. In our example it is MyVar=1;. This sets MyVar to 1 for the first time though the loop. The second part is the part that keeps the loop running. Our example is MyVar<101; as long as this statement is true the loop keeps running, notice that the . The last part is the logic that increments the variable, MyVar++. ><101; as long as this statement is true, the loop keeps running. Notice that the compairsion is less than 101, we could have used <= 100 as well. The last part is the logic that increments the variable, MyVar++; In PBasic we can step the variable up by a number other than one by using the STEP statement: for MyVar = 1 to 100 STEP 2 debug "MyVar=", dec5 MyVar, crnext In C this would look like this: for(MyVar=1;MyVar<101;MyVar+=2) {printf("MyVar=%5d\n",MyVar); } Notice theMyVar += 2 in the step part of the for statement. While LoopsWhile loops are used when the programmer does not know when the loop is going to end. In PBasic the loop looks like: MyVar = 0 do while MyVar < 100 debug "MyVar=", dec5 MyVar, cr MyVar = MyVar + 1loop In C the loop would look like: MyVar = 0; while(MyVar<100) {printf("MyVar=%5d\n",MyVar); MyVar++; } If MyVar would have been 100 or greater the loop would never have executed. The while loop is also used for an infinite loop: while(TRUE) {printf("Loop forever\n"); } Program Block and Variable ScopeIn PBasic there isn t a concept for a program block. In C is it a chuck of code that begins with a open curly bracket ({) and ends with a close curly bracket (}) The program block is just a method to highlight chunks of code. At the beginning of these blocks we can define new variables. These variables "live" for the in the code block and nothing can refer to the variables outside of the block. An example of this block is: int main(void) {int MyVar; for(MyVar=0;MyVar<100;MyVar++) { int MyVar2; MyVar2 = MyVar*2; } printf("MyVar2 = %d\n",MyVar2); } The variable MyVar2 only lives inside the for program block. Once we leave the program block we loose the MyVar2. The printf statement will cause an error in the compile time, since the program is outside of the for block and does not know about MyVar2. Another thing to point out in our example is MyVar2 is created and deleted every time though the loop. Goto and GosubIn PBasic we should have gotten use to writing code without the goto statement, so we will not cover them here. In most of the robot code that we have used in previous years, we may not have written a subroutine. A subroutine is a piece of code that we can execute outside of the main program and return to where we were at. An example of a PBasic subroutine would be this: Do If rc_sw5 = 1 then Gosub AddOneToMyVarAndCehck EndifLoop AddOneToMyVarAndCheck: MyVar = MyVar + 1 If MyVar > 100 then MyVar = 100 EndifReturn If the rc_sw5 is on, then we are going to jump to the label AddOneToMyVarAndCheck and run the code from that point until we reach a return statement. Then we will return to the place we left from. In C we have functions that do this work. Instead of the label, we are going to define a function. The function will look very much like the main function we saw in the first program we wrote. The function will look like this: void AddOneToMyVarAndCheck(void) { MyVar++; if(MyVar > 100) { MyVar = 100; }} In order to call this function we would either place this function before main, or place declaration of this function before our main program function. Example: int MyVar; void AddOneToMyVarAndCheck(void) { MyVar++; if(MyVar > 100) { MyVar = 100; }} int main(void) { AddOneToMyVarAndCheck();} Or we can do this: int MyVar; void AddOneToMyVarAndCheck(void); int main(void) { AddOneToMyVarAndCheck();} void AddOneToMyVarAndCheck(void) { MyVar++; if(MyVar > 100) { MyVar = 100; }} Notice in the second example we have placed the line, void AddOneToMyVarAndCheck(void); before main. This tells main that somewhere in the file we have defined the function AddOneToMyVarAndCheck and this is what the function looks like. The function we have defined takes no parameters in and returns nothing out. If we wanted the function to return a value we would place the value type in front of the function name and we would use the return statement to return the value, an example of our new function would be: int AddOneToMyVarAndCheck(void) { MyVar++; if(MyVar > 100) { MyVar = 100; } return MyVar;} In our new function we will return an int type return the value of MyVar. This is what the last return statement will do return MyVar;. Here is an example to call this function: int MyVar; int main(void) { int MyNewVar = 0; MyVar = 50; MyNewVar = AddOneToMyVarAndCheck(); printf("MyVar = %d MyNewVar=%d\n",MyVar, MyNewVar);} To input variables into the function we need to declare the variables in the parentheses after the function name. An example: int AddOneToMyVarAndCheck(int Var, int MaxVar) { Var++; if(Var > MaxVar) { Var = MaxVar; } return Var;} To call this example we will need to pass in either two variables, two values, or a variable and a value. This example we will pass in two values: int main(void) { int MyNewVar = 0; MyNewVar = AddOneToMyVarAndCheck(5, 100); printf("MyNewVar=%d\n", MyNewVar);} When we pass in variables like this the variable we pass in remains the same value after the call, even if we change it in the function. If we used this code here: int main(void) { int MyVar = 5; int MyNewVar = 0; printf("MyVar = %d MyNewVar=%d\n", MyVar, MyNewVar); MyNewVar = AddOneToMyVarAndCheck(MyVar, 100); printf("MyVar = %d MyNewVar=%d\n", MyVar, MyNewVar);} Inside of the AddOneToMyVarAndCheck function we increment the variable for MyVar but when the program returns from the function into main MyVar is not changed. This is something called passing by value. The value passed in is transferred to the function but not changed. In order to change the variable inside the function we will need to use something called passing by reference. We will not get into the low level details as to what is happing, but just display an example, the new AddOneToMyVarAndCheck will look like this: int AddOneToMyVarAndCheck(int* Var, int MaxVar) { *Var++; if(*Var > MaxVar) { *Var = MaxVar; } return *Var;} To call this new function we will need to add an ampersand (&) to the Var being passed in. int main(void) { int MyVar = 5; int MyNewVar = 0; printf("MyVar = %d MyNewVar=%d\n", MyVar, MyNewVar); MyNewVar = AddOneToMyVarAndCheck(&MyVar, 100); printf("MyVar = %d MyNewVar=%d\n", MyVar, MyNewVar);} Now the first print of MyVar will show 5, but the next one will show 6. Global VariablesIn PBasic every variable is global in other words we can use every variable that we define in our program at any point in our program. In C we have more control over our variables as we have seen in the program block. If we want to define a variable that we can use anywhere in our program we would define it outside and in front of the main function, an example of this is: int MyVar; int AddOneToMyVarAndCheck(void) { MyVar++; if(MyVar > 100) { MyVar = 100; } return MyVar;} int main(void) { int MyNewVar = 0; MyVar = 50; MyNewVar = AddOneToMyVarAndCheck(); printf("MyVar = %d MyNewVar=%d\n",MyVar, MyNewVar);} Notice that we can now use the variable MyVar everywhere in our program, both in the function and in the main program. ConclusionHopefully this will give us a good start at the conversion from PBasic to C. In further pages we will be discussing more functions as well as how the actual robot controller is going to work. Hey if you would like to mail stuff or suggest alternate spellings of
things on this site send them to: This site and all of the artwork on it is Copyright © 1993-2002 Jim Wright. All them rights reserved! |