Skip to main content

Beginners guide to Amiga Basic

I suddenly found this urge to dig up my old Amiga and play around with it. I called up my parents and went over to their house. What I assumed was an Amiga and a screen, was boxes upon boxes of floppys, cords and other junk. What I also found in there was three books on Amiga Basic programming which inspired me to write this blog post1.

Books on programming in Amiga Basic

Amiga Basic was shipped with the operating system Workbench version 1.1-1.32. When Amiga OS 2.0 was released in 1990 Amiga Basic became obsolete. It had a bug preventing it from working properly on 32-bit CPU and was instead replaced with Arexx. If you want to run Amiga Basic programs on Amiga OS 2.0 or better you need to use another intepreter or compiler.

One of the most interesting things about the original Amiga Basic intepreter is that Microsoft created it, so I think this is was my first interaction with the Redmond Giant.

The Amiga Basic IDE

The Amiga Basic came with a couple of high end features

  • Subprograms had scope. In short, variables declared in a procedure were local to that procedure and not global.

  • You did not have to print out line numbers. The program would execute lines from top to bottom.

  • You could create labels where the program execution could jump to with names, and not numbers. This makes the program easier to maintain.

  • You could open files and write to files. You could even communicate on the RS232 serial port.

  • There was a rich library of Amiga functions where you could access Amiga specific features like SOUND, SAY, graphic libraries like LINE, CIRCLE, PAINT and OBJECT that you could use to create graphical animations.

I've also heard it rumored that you could inline assembler, and call assembler code directly, but this functionality was so buggy that it in the end was useless.

Your first program

We are now going to dive into code written for a language that has not been working with any hardware or operating system released last 25 years. However, you can still get a copy of Workbench 1.2 with the Extras disk from Amiga Forever, and with an emulator try out this fascinating programming language from Microsoft.

This is Hello World in Amiga Basic.

CLS
PRINT "Hello World!"
END

Clear the result window, print the text and end the program.

  • CLS is the command to clear the result window.
  • PRINT outputs text to the screen.
  • END indicates the program is done. This is optional, when the list is EOF then the program is inded.

Amiga Basic: Hello World

Ok Ok. Every time I save or bring up the LIST window the intepreter tells me "Ok".

Variables

In Amiga Basic you have floating point numbers, integers and strings.

Type Example
float Numbers with decimals: 3.0, -0.05, 3.14
integer Numbers: 3, 0, -345
string Multiple characters: "Hello World!", "Cheers!", "My dog is Sam"

It is the declaration of the variable that decides what type it has. Float is the default type. You add a % suffix if you want an integer or a $ suffix for a string.

This program will calculate the area of a rectangle.

CLS

DIM w%,h%,a% LET w%=12 LET h%=4 LET a%=w%*h%

PRINT "With the width "; w% PRINT " and the height "; h% PRINT " you have the area "; a%

END

Here I specify explicitly that I want integers, even though it would have worked just as fine with the default value type, float.

  • DIM can declare several variables on the same row. The %-suffix indicates they are integers.
  • LET lets you assign values to variables
  • PRINT lets you output several values on one row with ;

Amiga Basic: Area

PRINT is a confusing command as it outputs spaces around identifiers. This makes output formatting very hard sometimes.

You can also have constants in your program and read them in as data. This is done with the commands DATA and READ.

CLS

DIM r,a LET r=5 READ pi LET a=rrpi

PRINT USING "With the radius ##.##"; r PRINT USING "we have the area ##.##"; a

DATA 3.14 END

If you don't add enough of ## in the print using, you're going to get some nasty % characters by the intepreter.

  • READ take the value from DATA and put it in a variable called pi
  • PRINT USING defines a format where the number 5 will be shown as 5.00
  • DATA constants that can be read by the program. This can appear anywhere in the code, but is most often put in the end.

Amiga Basic: Circle

In the LIST window I have two newlines before DATA. This is because the editor has a bug where you sometimes can't remove lines. It complains about the empty lines being too long.

Read input from user

You use the keyword INPUT to read input from the user. This program will ask for you shoe size and print it back to you.

CLS

PRINT "What is your name?" INPUT n$ PRINT "What is your shoe size?" INPUT size

PRINT "Hello "; n$ PRINT "your shoe size is ##.##"; size END

This is actually the first program that I ever typed into the intepreter from a computer magazine called DatorMagazin3. The article was showing the same program in several different programming languages.

  • INPUT declares a variable at the same time as assigning value from user input.

Amiga Basic: Shoe Size

The INPUT command puts a questionmark before the user input and there is no way to modify this behavior.

Control flow

The amazing thing about Amiga Basic is that IF works with blocks. In older Basic dialects you only had the option to control flow by sending program execution to a specific label.

CLS

READ max% DIM number%, guess%, guesses%

PRINT "The number is between 1-1000."

LET number% = INT(RND * max%) + 1 LET guess% = 1 LET guesses% = 0

WHILE guess% <> number% PRINT "Guess the number" INPUT guess%

IF (guess% > number%) THEN PRINT "Your guess was too high" ELSE PRINT "Your guess was too low" ENDIF

LET guesses% = guesses% + 1 WEND

PRINT USING "You found the number in ## tries"; guesses% DATA 1000 END

I remember this being a learning exercise from the book "Turbov├Ągen till Pascal" when I was learning Pascal.

  • INT(RND * max%) Will return a random number between 0-999
  • WHILE Will keep looping while the condition is true
  • WEND Marks the end of the while block

RND will actually give us the same random sequence every time, so this game is not very fun after you've found out the number is always 122.

Amiga Basic: Guess The Number

There is a bug in this code causing it to say our guess is too low, even when it is spot on. Can you propose a fix to that bug?

For-loop

A foor loop starts at a number and counts up until it reaches max. This program will type out a pyramid of the height that you specify.

CLS

DIM stars$

PRINT "Enter the height of the pyramid" INPUT height

FOR i=1 TO height LET stars$ = ""

FOR j=1 TO (i + i - 1) LET stars$ = stars$ + "*" NEXT j

PRINT SPC(height - i) stars$ NEXT i END

  • FOR initializers a counter at an index and runs until counter equals TO argument
  • NEXT will increment the counter and return program execution to start of the FOR block
  • SPC(height - i) will give height - i number of spaces to output in front of the stars

Amiga Basic: Pyramid

And we can also count down with the FOR loop. Here we use it to calculate the factorial of a number.

CLS

DIM result

PRINT "Calculate the factorial of" INPUT n

LET result = 1 FOR i = n TO 1 STEP -1 LET result = result * i NEXT i

PRINT n "! = " result END

  • STEP -1 allows the FOR loop to count down instead of up.

Amiga Basic: Factorial

Lucky we picked a small number. Who knows what will happen if the result variable overflows.

Strings

You define a string value by naming the identifier with a dollar sign $ in the end. There are some string functions built in to perform basic string operations.

This program will take a number as encryption key, and a string, and with ceasar cifer encrypt the string.

CLS

READ alphabet

DIM phrase$, result$, encChar$, encKey

PRINT "Enter the encryption key (number)" INPUT encKey

PRINT "Enter the phrase to encrypt (capital letters) INPUT phrase$

FOR i = 1 TO LEN(phrase$) LET encChar$ = CHR$(((ASC(phrase$) + encKey) MOD alphabet) + ASC("A")) LET result$ = result$ + encChar$ LET phrase$ = RIGHT$(phrase$, LEN(phrase$) - 1) NEXT i

PRINT "Encrypted prase: " result$

DATA 25 END

I write my own encryption algorithm and I am proud of it.

  • LEN(phrase$) returns the length of the string
  • CHR(i) converts an ASCII number to string
  • ASC(s$) returns the ASCII number for the string
  • MOD is a modulus operator
  • RIGHT$(phrase$, LEN(phrase$) - 1) RIGHT picks a number of characters from the right of a string. The whole expression will remove first character from a string.

Amiga Basic: Pyramid

Completely uncrackable.

Arrays

Amiga Basic has no support at all for arrays, but you have direct access to the memory where you can read and write values as you please.

This program will calculate first 10 numbers from Fibonacci and output them to the screen.

CLS

READ max

DIM fib%(max)

LET fib(1) = 1 LET fib(2) = 2

FOR i=3 TO max LET fib(i) = fib(i - 2) + fib(i -1) NEXT i

PRINT "Fibonacci"

FOR i=1 TO max PRINT fib(i) NEXT i

DATA 10 END

  • DIM fib%(max) You can dimension a variable with custom size.
  • fib(1) And you can index into a position in a variable.

Amiga Basic: Fibonacci

It is not arrays per se, but it will work well enough.

Procedures

Amiga Basic has this feature where you can split your program into sub programs. These sub programs have their own scopes meaning they do not share variables as labels do. This makes it easier to maintain.

CLS

READ w

SUB Title STATIC PRINT "*** AMIGA IS NOT DEAD, ONLY TAKING A BREAK ***" END SUB

SUB Separator(stars) STATIC PRINT STRING$(stars, "*") END SUB

Separator(w) Title Separator(w)

DATA 46 END

Amiga Basic: Procedures

The SUB is not really a procedure in the traditional sense, but more seen as a sub program that you can send arguments to.

Here is another example performing a bubble sort

CLS
READ max

DIM SHARED numbers(max)

SUB CreateList(max) STATIC FOR i=1 TO max LET numbers(i) = INT(RND * 100) NEXT i END SUB

SUB SwapValues(i%, j%) STATIC LET numbers(i%) = numbers(i%) XOR numbers(j%) LET numbers(j%) = numbers(i%) XOR numbers(j%) LET numbers(i%) = numbers(i%) XOR numbers(j%) END SUB

SUB Sort(max) STATIC FOR i%=1 TO (max - 1) FOR j%=i%+1 TO max IF numbers(i%)>numbers(j%) THEN CALL SwapValues (i, j) END IF NEXT j% NEXT i% END SUB

SUB PrintList(max) STATIC FOR i=1 TO max PRINT numbers(i) NEXT i END SUB

CreateList(max) Sort(max) PrintList(max)

DATA 20 END

Amiga Basic: Bubblesort

  • DIM SHARED Makes the numbers array globally accessible
  • CALL can be used to invoke SUB procedures

Closing comments

Since my first programming language was Pascal, I have never been a fan of Basic. When I was young I had a friend that did a lot of programming in QBasic (DOS) but I could never really get the hang of it. I simply liked Pascal better.

As a forensic excersise I find Amiga Basic to be quite fun to play around with. That is very much because it is an official Microsoft Basic implementation, and I don't think I've been this close to early Microsoft software before. That would be MS-DOS 6.0.

Microsoft Amiga Basic is missing some crucial parts that I need in a modern programming language.

  • I need to be able to define types, records or objects. Amiga Basic is bound to its default types, int, float and string.

  • Amiga Basic has a function construct but that does only allow 1 statement. I need functions that allow blocks of code for their body, and that works with recursion.

  • You can access and manipulate the memory directly which is insanely dangerous. However I would love a construct like new to reserve memory space for data and a pointer to that memory space. That would enable us to create linked lists.

  • Amiga Basic is an intepreted language, but it would be nice if you could create a library of procedures/functions that could be imported from other languages.

Of course there are still operations in the API that I haven't covered here, but I think this guide goes through the bulk of what you can do with the language. If you have any questions please ask them here and I will see if I can dig out an answer from the reference material.

Thank you!


Footnotes


  1. I will never get over that my father threw away his books on IBM-DOS 3 and COBOL85. Those things are unforgivable. 

  2. I find it curious that most of these old computers shipped with a way to program them, often some sort of BASIC clone. You were not dependent on others to create programs for you, but you could create them yourself. 

  3. DatorMagazin was a computer magazine about C64 and Amiga in the 80/90's. The imaginative name means literaly "computer magazine" in English. 

comments powered by Disqus