========= Section 2: A simple tutorial: transitioning to Slang from BASIC ========= If you're familiar with higher-level languages you can probably skip this part. Some people however may be familiar primarily with programming in Commodore BASIC, and that's who this section is targeted at. This section introduces some of the higher-level language features in Slang you'll need to be aware of, in comparison with BASIC. This is also a little tutorial on using Slang, so there are lots of examples below to try out. Once you've gone through them you should be well on your way to using Slang like a pro. Note: If you find this tutorial useful -- or if you find it totally confusing -- or if you find it anything at all -- please write me or post a note to the forum, and let me know. I'd love to hear from you. Heck, right now I'd love to hear from anybody! But feedback is very important, and it helps me to know what works and what doesn't. Interpreted vs. Compiled ------------------------ BASIC is an interpreted language, whereas Slang is a compiled language. In BASIC, you write the code, then RUN it, then errors are caught as they are encountered (Syntax Errors, Overflow Errors, etc.). You can break a program while it's running, have a look at some of the variables, change things around, then CONTinue running the program. In a compiled language like Slang you write the code, then compile it into machine language, then run that machine language program. You don't actually run the code you've written -- the compiler converts the code you've written into machine language, which you then run. So there are actually two parts to the program, that you can for example save to disk: the _source code_, which is the part you write, and the _object code_, which is what the compiler produces. The object code is what other people will run when they run your program. In Slang, source code files end in '.s', as in "spritedemo.e.s", and object files end in '.o', as in "spritedemo.e.o". As to errors, errors such as Syntax Errors are caught during the _compile_ phase, before ever running the program. Other types of errors (called runtime errors) are never caught at all -- in general if there are errors in your program it will keep on running, or may lock up the machine entirely! But Slang is designed to handle this, so that you won't lose your program. Tutorial lesson #1: So here is the first thing to try: we're going to write a program that will crash, so you can lose your fear right away of causing some huge problem. To start up slang, load and run the main program (slangb1.9.o or whatever it might be). Once you've got the editor running, type in the following program: sprint "here comes a crash!" donebrk Then press F1 to compile the program. If there are no errors, you will get a "compile successful" message. Now press F4 to run the program -- crash, right? Go ahead and reset the machine (don't power it down; just press the reset button). Then type sys 54016 and you should pop back into Slang. Slang stores itself up in SuperRAM, so you don't need to worry about losing your program because of a crash, and if you want to try something just go ahead and experiment! Variables --------- In BASIC variables are created on the fly -- you just say "10 a=1" and off you go. In languages like Slang, you have to declare your variables before using them. Let's take a dumb BASIC program, and convert it to Slang: 10 FOR B=1 TO 3:PRINT "BLAH ";:NEXT 20 PRINT CHR$(13)+"PRESS ANY KEY..." 30 GET A$:IF A$="" THEN 30 40 END Obviously lines 20-40 are not needed, but I put them in for a reason. Here's a Slang version: byte b for b=1:3 sprint "blah " next sprint !13"press any key..." waitchar done Tutorial lesson #2: Go ahead and type this program into the Slang editor, press F1 to compile, and press F4 to run. Easy! The first line of this program _declares_ the variable. Part of the reason you have to do this is that there are different _variable types_ available. In BASIC, you can have floating-point variables, integers, and strings, and the name itself tells basic what type of variable it is: a=10 ;numeric (floating point) variable a%=10 ;numeric (integer) variable a$="10" ;string variable As you probably know, the only reason to use integer variables is with arrays, to save memory, because an integer array takes less memory than a float. Otherwise, a plain integer variable takes exactly as much space as a regular variable, and is actually slower for calculations because all calculations in BASIC are floating-point calculations. In Slang, this is not the case. The variable type not only changes how much space is used but also how the variable is manipulated. In Slang, adding integers is much faster than adding floats together, and the integers take less space. For example, if you change the line byte b in the program above to float b you'll find that the program becomes larger, and it's also much slower (although you won't notice that in a simple program like this). Tutorial lesson #3: Change b from a byte to a float, compile, and see what happens. The different variable types available in Slang are: byte - 1 byte, signed numbers in range -128..127 ubyte - 1 byte, unsigned, range = 0..255 int - 2 bytes, signed, range = -32768..32767 uint - 2 bytes, unsigned, range = 0..65535 float - 5 bytes, signed, range = well, the usual BASIC range In general, the smaller variables are also faster, so you'll often choose the simplest variable that meets your needs. Just a few other things are worth noting. Unlike BASIC, variables can also have really long names, like: uint ThisIsAVeryLongVariableName b = b+ThisIsAVeryLongVariableName Note also that variables can mix upper and lower case (the compiler is case-insensitive), and can mix variables of different types (you can add a byte to an int, for example). And once a variable is declared, that's it -- you can't re-define a variable as a different type. One other thing to notice is that there is only one statement per line. Unlike BASIC, you cannot put multiple commands on the same line. Loops and such -------------- As is apparent in the above program, the for-loop in Slang is pretty similar to the BASIC for-loop. You can also put a "step" in there: for b=1:10 step 3 There are two other loop structures available in Slang (and many other lanauges): while-loops, and repeat-loops. Here's an example: b=1 while b<4 sprint "blah " b=b+1 endwhile This program does exactly the same thing that the for-loop does in the original program: while the expression b<4 is true, it performs whatever code is in-between the "while" and "endwhile" statements. The repeat statement is very similar: b=1 repeat sprint "blah" b=b+1 until b>3 A repeat-statement always executes at least once, because the expression check is at the end of the loop. The way to think about all these things is pretty simple: while [expression] While [expression] is true [code] <------------- Execute this block of code endwhile between the while and endwhile statements One thing that Slang does not have is a GOTO statement. You can actually do gotos using assembly language, but it turns out that you can handle all the things you might use GOTO for using for/repeat/while-loops and the if-endif structure discussed down below, and your programs will be easier to debug. Tutorial lesson #4: Replace the for-loop in the example code with a) a while-loop, and b) a repeat-until loop, but make it print out the text five times instead of three. Compile and run each case to verify that it works. Ending a program ---------------- You'll notice that the program ends with the line "done". In BASIC, putting an "END" in is optional. In Slang, it is required. It tells the C64 how and when to exit the program. If you'd like to see what happens when you leave it out, go ahead and try it! Just remember that "sys 54016" will restart Slang after you reset the computer. We can now explain the last few lines as well. The command "waitchar" simply waits for a key to be pressed. Without this line, the program would immediately end and return you back to Slang. The "waitchar" would not be necessary if this program were being called from, say, BASIC -- in that case, you would probably want control to return to BASIC immediately. But when running programs directly from the Slang editor, you'll usually want to put a line like this at the end of the program. Tutorial lesson #5: As a test, go ahead and comment out that line (place a ";" before the waitchar), re-compile, and see what happens when you run the program! Print ----- The little program above used the "sprint" command. There are actually two print commands in Slang: print, and sprint. Sprint -- Simple Print, or String Print -- is a simple print command that only prints strings (not numbers). As we shall see shortly, the regular print command contains certain things in a _library_, which requires an extra step, and will make your programs larger. For the moment though we can focus on sprint. Printing a string in Slang works much the same in BASIC, with just a few little twists. Unlike in BASIC, you cannot embed special characters inside the quotes, like 10 PRINT "{ctrl-2}{shft-clr}nice white text on a clear screen." Instead, in Slang, you have to use the character codes directly; in BASIC, you could also do the above as 10 PRINT CHR$(5)+CHR$(147)+"nice white text on a clear screen." In Slang, you simply use a ! instead of chr$, so this would look like sprint !5!147"nice white text on a clear screen." The above command has one key difference from the BASIC version, however: in BASIC, PRINT normally prints a chr$(13) at the end of the line, whereas sprint will not. It turns out that there's actually two more print commands in Slang, though: println and sprintln. These work exactly the same as print and sprint, but print an extra [RETURN] character at the end. Tutorial lesson #6: Go ahead and try replacing "sprint" with "sprintln" in the example program, and see what happens. Tutorial lesson #7: Modify the example program to print out the text in cyan. How about light green? There's one more trick to print and sprint: you can specify _where_ on the screen to print: sprint(0,20) "some text" will print the text at row=0, column=20. Tutorial lesson #8: Modify the program to print the text to the middle of the screen. In contrast to sprint, print can print numbers and strings, and you can stick them all together on a single line. The catch is that many of the routines needed to do this are in a _library_. This library is a file on the disk, containing special routines. In general, libraries can be source code, object code, or a special kind of file (a relocatable file) for use by the linker, which I won't talk about here. Tutorial lesson #9: What we are going to use is a simple source code file. Try typing in the following code, and compile and run it: byte b for b=1:10 println "b=" b next print "press any key..." waitchar done put 'putcore.e.s' The two critical differences here are 1) we are now using print instead of sprint, and 2) the "put" command at the end of the file. For now, instead of going into detail on PUT, let's just say that you need that line at the _end_ of your code -- after the done statement -- if you want to use the full print command. Notice that we have put both a string and a number on the print line, similar to BASIC. You can also separate these with commas, if you like: print "b=",b It just depends on which way you think is clearer. You can also print to any part of the screen: print(b,20) "this is row "b Tutorial lesson #10: Replace the println statment with the above "this is row" statement, and see what happens. As you can see, print is much more powerful and flexible than sprint, but the downside is that you need to PUT the core library in there, which increases compile time and makes the program much larger. Experience will help you figure out when you want to use one or the other. The core library ---------------- Above we used the core library, using the line put "putcore.e.s" at the end of the program (whether you use ' or " quotes doesn't matter, incidentally). This is a very important library and is needed for more than just print. Tutorial lesson #11: Multiplication and division of bytes/ints requires this library, and you will get an error if you don't include the core library. (Print will also generate an error.) Try the following program: int b b=10 b=b*2 done Now compile it, and you will get an error at the multiplication. Then add the line put 'putcore.e.s' to the end of the program, compile... and it will work. And since you're including the core library anyways, you can go ahead and print out b if you want to. Why use a library? If you know BASIC, you know that a command like "print" actually calls a routine in the BASIC ROMs to do its thing. The BASIC ROMs are, for the most part, one big library, but they are in ROM instead of in a disk file. Sometimes machine language programmers will call these BASIC routines instead of writing their own. Similarly, in a compiled language like Slang, sometimes it makes sense to call a common routine to perform some task. A library is nothing more than a collection of useful routines. Arrays and Strings ------------------ We're just about done here. I'm not going to cover _all_ of the available commands; the goal here is to get across the major commands, and then you can browse the slangref.txt document to check out other commands. So I'll just touch on the remaining topics at this point. Arrays in Slang work much the same as arrays in BASIC. You declare them very similarly to other variables: int b ;regular variable int c(20) ;array This is similar to using the DIM statement, if that helps. There's just one thing to remember: array indices start at 0. In the above declaration, you can address c(0), c(1), c(2), ... c(19), like c(19) = 1000 but c(20) = 1000 will be incorrect (and may cause a crash). There are 20 elements total: 0 through 19. If it's too confusing, then one thing you can do is to add one extra element to any array -- like, use "int c(21)" -- and not worry about it. Strings also are really similar to BASIC, but you're going to have to get one thing straight in your head: strings are really just bytes. There is no "string" type, like byte/int/float; strings are just bytes. You already know this, from BASIC: d$="a" ;treating letter "a" as a string d$=chr$(65) ;treating letter "a" as the number 65 The letter "a" is really just a number -- 65 in this case. This works the same way in Slang: ubyte d d = "a" ;a "string" d = 65 ;a number That's fine for just one character, but that's not a string. In Slang, a string is just a byte array: ubyte d(20) d$ = "hello" ;treat as a string d(0) = "y" ;change string to "yello" d(0) = 67 ;change string to "cello" In this example, d is a byte array. You can treat it as a string, or as a list of numbers. As in BASIC, the "$" tells Slang to treat the variable as a string -- I won't go into the details about this, but I think the meaning is pretty clear from the above example. Tutorial lesson #12 Here's a simple program using strings to try out: ubyte d(20),i d$="hello" println "d$=" d$ d(0) = 67 println "d$=" d$ for i=0:5 println d(i) endfor waitchar done Go ahead and play around with it -- try adding 1 to each element of the string, etc. One important thing to note: when you run the program, you'll notice that the last number printed in the for-loop is a 00. With strings, the very last element will be zero -- this is what tells Slang where the end of the string is. If you overwrite this ending zero, you'll generally get a whole bunch of garbage. So... Tutorial lesson #13 Change the line d(0) = 67 to d(5) = 67 and see what happens when the string is printed. This overwrites the ending zero byte, and should in general print out a bunch of garbage. Sometimes, if you're lucky, there will be another 00 somewhere in the array! If-elseif-endif --------------- The if-then structure: if a=10 do something elseif a=11 do something else endif It's similar to the BASIC command, except that you have an elseif or endif command to mark the block of code to be executed, just like while and repeat. Subroutines ----------- In BASIC, you are familiar with GOSUB -- it calls a subroutine, and then RETURN returns back to the place of the subroutine call. Slang subroutines are more sophisticated, but the idea is the same and overall they are pretty similar. A subroutine is like a mini-program: you can define variables, have a bunch of statements, etc. The neat thing is that these variables and statements are _local_ to the subroutine -- they "belong" to the subroutine, and do not interact with other subroutines. This allows you to organize your programs efficiently. Just like a variable, you have to define a subroutine. And you need to end the routine using "endsub". With a subroutine, you can pass _parameters_ to the routine. For example, the graphics library has a routine called GrPlot, to plot a point. And it requires two parameters: the x- and y-position of the point to be plotted: GrPlot(x1,y1) Subroutines can also pass parameters _back_ to the calling routine. Once you "get" the idea of parameter passing, and of local variables, the rest is a cinch. Tutorial lesson #14: Type in and run the following program, which demonstrates the idea of local variables within a subroutine: byte b b=1 TestRoutine() ;Call the subroutine println "but in the main code, b is still "b waitchar done sub TestRoutine() ;Define the subroutine byte b ;create the _local_ variable b b=10 println "in the subroutine, b="b endsub ;end subroutine put "putcore.e.s" You can see what I mean about a subroutine being a mini-program. Within the subroutine you declare variables, have statements, and end it with an endsub. You don't really worry about what other routines or the main program does; the subroutine doesn't "see" them. So, a few observations: the "sub" keyword defines a subroutine. We _call_ the subroutine by simply typing the subroutine name in the main program. Once the routine finishes, the calling program continues executing where it left off. The subroutine declares its own variable b. Even though it has the same name as the variable in the main program, this is a _local_ variable; it "belongs" to the subroutine, not to the main program. Tutorial lesson #15 In this lesson, we'll try parameter passing. int x1,y1 x1=12 y1=20 AddEm(x1,y1) println "the result was " AddEm<-result waitchar done sub AddEm(int a, int b)<-int result result = a+b endsub put "putcore.e.s" (As before, <- is the backarrow key). In this example, the subroutine AddEm takes two _input_ parameters, a and b, and has one _output_ parameter, result. As before, all three of these parameters are local to the subroutine, so they could have the same name as variables in the main program. With the return parameter, what we are really doing is making a subroutine variable _visible_ to outside routines. Normally all variables and such inside a subroutine belong to the subroutine, and are not available outside of the routine; this is how to make specific ones available outside of the subroutine. Just as with input variables, there can be a whole list of output variables. Back in the main program, this is just another variable called AddEm<-result. You can use it in expressions, etc. just like any other variable: x1 = x1 + 2*AddEm<-result So in summary: a subroutine is like a mini-program, with its own variables and statements. But, you can pass parameters into the subroutine, and you can retrieve variables out of the subroutine, as needed. Subroutines are really helpful in organizing and simplifying programs, so it's well worth taking the time to understand them if you don't already! Saving object code ------------------ Once you've written a program, what do you do with it? What we're going to do here is save the _object_ code, and then load and run it. Tutorial lesson #16 (always need some multiple of 16, right?) Compile one of the example programs above (one that works!). Once it compiles successfully, press F7 to enter the disk menu. First, save the source code by pressing "s". Go ahead and enter some filename; the program will automatically append a ".s" to the filename. Second, save the object code by pressing "o". You'll see the same filename as default, so go ahead and press return. If you now list the directory, you should see two new files: one with a .s, the other with a .o. You can now load and run the object code totally indepently from Slang. Exit back to the editor. We are now going to exit to BASIC: press shift-ctrl-<- (backarrow, to the left of the '1' key), and you should be back at the BASIC prompt. If you'd like to try your program from here, you can type "sys 4096". Now reset the machine. Go to the disk directory, and load your object file ,8,1. Your object code is a machine language file, just like other programs you may own or download. Once it's loaded, type "sys 4096" to run it. (By default, Slang programs are located at 4096, but it is easy to locate them elsewhere, such as 32768 or 49152, or even make it so you can RUN them from the BASIC prompt.) When you're done, type "sys 54016" to return to Slang. And that's it! You should now be able to write, run, and save Slang files and be well on your way to writing new programs. If you have any problems or questions, don't hesitate to write me or to post to the forum! Good luck!