BASIC Interpreter

Contents | Back: Software Development | Next: Final Notes

The latest version of the firmware for my 6502 home computer can be found in the firmware directory of the project. It currently implements a tiny  BASIC interpreter which lets you implement - guess what - a blinking LED!

10 led on
20 sleep 500
30 led off
40 sleep 500
50 goto 10

Or a more complex program like a number guess game:

100 print "Guess my number (1..100)!"
110 let n = rn % 100 + 1
120 let i = 0
130 put "Your gess: "
140 input x
150 let i = i + 1
160 if n == x then goto 220
170 if n > x then goto 200
180 print "No, my number is smaller."
190 goto 130
200 print "No, my number is bigger."
210 goto 130
220 print "Congratulations, ", n, " was my number!"
230 print "You needed ", i, " guesses."


Here is a photograph of the program running on my 6502 computer: Homecomputer 6502 Guess Program

Implementation

The main function of the BASIC interpreter is quite simple. First all IO subsystems are initialized, then some informative messages are printed and then an infinite loop is entered. This loop is called a REPL - read, evaluate, print loop - because it reads one line of input from the keyboard, evaluates it, prints the results and then repeats. In this case the readline() function is used to get input from the user and this line of input is then send to the BASIC function interpret() to evaluate it and print the results:

int main() {

  acia_init();
  lcd_init();
  led_init();
  keys_init();
  basic_init();

  acia_puts("6502 HomeComputer ready.\n");
  lcd_puts("6502 HomeComputer ready!\n");
  sprintf(print_buffer, "%u bytes free.\n", _heapmemavail());
  lcd_puts(print_buffer);
  lcd_puts("Ready.\n");
  lcd_cursor_on();
  lcd_cursor_blink();

  for (;;) {
    char * line = readline(NON_INTERRUPTIBLE);
    interpret(line);
  }

  return 0;
}

The interpret() function first checks if the line starts with a line number (in this case a new line is added to the BASIC program) or is a command that should be executed directly. In this case the execute() function extracts the command and the arguments, searches for the command function and calls it with the command arguments:

void execute(char *s) {
  unsigned char command;
  char * args;
  reset_interrupted();
  s = skip_whitespace(s);
  args = find_args(s);
  command = find_keyword(s);
  if (command != CMD_UNKNOWN) {
    command_functions[command](args);
  } else {
    lcd_puts("Unknown command!\n");
  }
}

Here is an example of a simple command FREE which prints the number of free bytes to the LCD screen:

void cmd_free(char *) {
  sprintf(print_buffer, "%u bytes free.\n", _heapmemavail());
  lcd_puts(print_buffer);
}

Once the command has been executed, the REPL is reiterated again.