I used to write small programs in on my Commodore 64 as a child.
I thought I'd take another look at it. VICE is a good C64 emulator, and is already packaged for NixOS.
nix-env -iA nixos1803.vice x64sc # This is the Commodore 64 emulator in accurate mode
The first thing to notice is that everything is capitalized. If you hold the shift key and press a character, intending to type a capital, you'll instead get some weird character, so don't do that.
The Commodore 64 functions as a REPL. You can interactively enter commands to execute them immediately. Usually you need to put PRINT before them to make them not a syntax error, however.
PRINT "OY OY SAVALOY."
If you want to instead store a command in memory, so that you can run it later, you write a line number in front of it. If you need to erase a line, just put in that line number with no code after it.
Having stored some commands in memory, you can view them using LIST, run them using RUN, and save them to your output device (usually a cassette tape) using SAVE.
Comments use the REM command, which stands for remark.
0 REM A PROGRAM, STORED IN MEMORY 10 PRINT "OY OY SAVALOY." 15 REM THE END OF THE PROGRAM LIST RUN
Line numbers must be integers from 0 to 63999, so make sure to leave some gaps between them in case you need to write more than you thought.
You don't need to declare variables. You can just assign them using =. There is an optional LET keyword you can use here.
The manual recommends omitting LET, because it takes up unnecessary memory. However, = is also overloaded to mean equality, so you might sometimes find it useful.
10 X = 5 20 PRINT X RUN
You can allocate fixed length arrays using DIM(10, 10). These can be multi-dimensional.
There are three functions to allow you to keep some data inside the program code:
- constants inside the program code
- set variable from data statements
- go back to start of data
Negative numbers are represented in two's complement.
The standard number comparison operators =>< work.
There are three bitwise operations AND, OR and NOT. They also act as logical operators.
0 is false, other numbers evaluate to true. Similarly, "" is false, while other strings evaluate to true.
Built in number functions:
- absolute value
- e to the power of number
- round downwards
- natural logarithm
- random uniform float
- sign of number
- square root
- character to ASCII code and back
- convert number to text and back
- length of a string
- characters of whitespace
RUN starts from the first line number you have stored.
If you want to use a different entry point, you can use GOTO instead
GOTO 1000. This is probably more useful inside your programs, however.
There is a multiple jump variant of GOTO which switches on a variable to choose the target
ON X GOTO 1000, 2000, 3000.
Execution continues in ascending order by line number, until you reach some sort of jump or branch command.
The GOSUB command lets you be a bit more structured in your programming. It puts the calling line on the stack, jumps and continues executing until it reaches a RETURN command, then jumps back to the line from the stack (there is a limited stack depth).
There isn't any built-in support for jumping named labels, just line numbers.
GOSUB isn't the same as a proper function call, because the stack frame doesn't include local variables.
You can define functions using DEF FN:
DEF FN MyFunction(X) = X + 1} You can only use this inside your program code.
Functions can return numbers or strings. They only take one parameter, but can look at other variables.
Branching and Looping
There is IF-THEN, but no else statement. There are FOR loops which work a bit like a range.
0 REM FIZZBUZZ IN C64 BASIC 10 GOSUB 100 20 FOR X = 0 TO 100: GOSUB 200: NEXT 30 END 200 REM Print FizzBuzz 210 LET BUZZ = X / 3 215 LET BUZZ = BUZZ = INT(BUZZ) 220 LET FIZZ = X / 5 225 LET FIZZ = FIZZ = INT(FIZZ) 230 IF BUZZ AND FIZZ THEN PRINT "FIZZBUZZ" 240 IF BUZZ AND NOT FIZZ THEN PRINT "BUZZ" 250 IF FIZZ AND NOT BUZZ THEN PRINT "FIZZ" 260 IF NOT FIZZ AND NOT BUZZ THEN PRINT X 299 RETURN
The next command says which loop variable to move (if omitted, it increments the innermost loop). There's a limit of 9 levels of loop nesting.
- open or close a device
- choose output device
- read keypresses from the user
- read keypresses from somewhere else
- prompt user for input
- fetch data from somewhere else
- read program from storage device, or save it onto the device
- compare program on storage to program in memory
- current cursor position
- write to screen
- spacing when using print
- write somewhere else
- what happened to the last file operation
- time since power on
- real time
It's possible to incorporate coloured text in your program using key sequences, which you can print out.
You can also print out cursor key movements.
- get or set an integer at a memory address
- erase memory
- erase program
- list free memory