Simulating BASIC using C

Created 15th July, 2007 13:49 (UTC), last edited 15th July, 2007 15:41 (UTC)

I've decided to cut something out of one of the articles I'm working on, but thought it might be an interesting little thing in its own right.

As I've said before, the first programming language I ever learned was BASIC. Today I think those of us who used early micro-computer BASICs can't really remember just how bad things were, and of course the youngsters who grew up with anything more sophisticated don't remember the days of pre-object oriented programming let alone pre-structured programming.

It is practically impossible to teach good programming style to students that have had prior exposure to BASIC; as potential programmers they are mentally mutilated beyond hope of regeneration.

Edsger Dijkstra

I think that I might have only been scarred rather than “mentally mutilated beyond hope of regeneration”, but I guess I'll never know for sure.

What interested me though was whether I could come up with a set of rules that would turn a pretty well known language, C in this case, into the sort of language that old school BASIC was before local variables and sub-routine arguments were invented.

Here's my first try at a set of rules:

  • Every label or function name must be in the form L99999 — I.e. the letter 'l' followed by a number.
  • Only one statement per line — I.e. a semi-colon appears at the end of every line.
  • Here's the killer dual rule: Every line needs a label in the format given as per the first rule and all numbers must be in order — The lines in the program were sorted by line number and you were responsible for managing them. This rule almost destroys any chance of performing any type of refactoring or anything other than trivial maintenance.
  • No curly brackets after an if statement — You can have an if and an else, but no if else and you're not allowed statement blocks either. If you need to do anything more complex you need to define a label and use a goto to get there.
  • No function parameters — You're allowed to define functions, but not with arguments. This is how the BASIC command gosub worked. You have to use globals to pass in parameter values.
  • Every function must return void — To return a value from a function you have to use a global.
  • No switch, while or do/whiles — BASIC didn't have complex looping constructs.
  • You can use for loops — But only on ints. This is the one place you are allowed to use a block though, i.e. {}.
  • No local variables — Every variable must be declared at global scope, but you are allowed to initialise them upon declaration.
  • Only a single variadic parameter to printf is allowed — You can have something like printf( “hello” ); or printf( “hello %s”, name ); but not printf( “hello %s times %s”, name, times );
  • Only a single variadic parameter to sprintf is allowed — Just like the previous printf example.
  • Run it on old hardware — Computers in those days didn't have pipelined CPUs and they only ran at around 4MHz. In practice they were probably at least a million times slower than a modern PC.

I think if you follow these rules then you'll get a fairly good idea of the sort of thing that old-school BASIC programmers had to go through. My brain hurts just thinking about it…

Here are a few things to try.

n Bottles of beer in BASIC/C

You need to ask the user how many bottles of beer and then print that many verses.

One of the minor complicating factors is that you can't pipe output, so you are responsible for all paging. It's best to assume that only 24 lines can fit on one screen.

Sorry.

A calculator

Modelled on the WTF calculator problem, write a standard four function calculator. Whether you include a “memory” option or not is up to you.

A simple game

Early BASICs had all sorts of non-standard ways of placing the text cursor anywhere within the text window (doing graphics was even less standard). So, pick your favourite non-portable way of doing it in C and write one of those games where a snake travels around a maze and eats things to grow longer without eating itself or the walls.

You'll notice that the input method (scanf) doesn't really allow for this sort of interaction. You may need to go non-standard for that too, but for reliability (at least as far as computers running BASIC was concerned) you should program the input routine in assembly language as an interrupt.

You can simulate the BASIC functions PEEK (return the byte at a certain address) and POKE (write a byte to a certain address) using a char * pointer (if you need bigger values feel free to choose your own endian mode).

You may write a function in assembly so long as you use don't do anything outside the spirit of the rules for functions given above, for example no playing the stack frame.

I know this is a very hard problem because it's the one I did for my first ever software company many, many, many years ago.


Feel free to change any of the rules if you must, but give some proper justification along with it.


Categories: