Apple I BASIC as a Mac OS X Scripting Language

Update: Commodore BASIC as a Scripting Language for UNIX and Windows – now Open Source

Recently, we reconstructed a perfect copy of Apple I BASIC, the first piece of software Apple ever sold – in 1976. Now it is time to make something useful out of it. Wouldn’t it be nice if you could use Apple I BASIC to replace, say, Perl? Wouldn’t it be nice if you could do this:

$ cat reverse.bas
#!/usr/bin/apple1basic
10 DIM A$(100)
20 INPUT A$
30 FOR I = LEN(A$) TO 1 STEP -1
40 PRINT A$(I,I);
50 NEXT I
60 PRINT
70 END
$ chmod a+x reverse.bas
$ echo MICHAEL STEIL | ./reverse.bas
LIETS LEAHCIM
$

Here is Apple I BASIC as a scripting language for Mac OS X Intel:

apple1basic_osx.zip

Just yet another Apple I emulator for Mac? No, it is not. There are some very important differences:

  • The “apple1basic” executable is a statically recompiled version of the original binary. All code is running natively.
  • “apple1basic” plugs right into UNIX stdin and stdout.
  • You can pass “apple1basic” the filename of a BASIC program to run.
  • You can run BASIC programs like shell scripts.

Let’s play with it for a bit. First, copy “apple1basic” to /usr/bin:

$ sudo cp apple1basic /usr/bin

Let’s try direct mode first:

$ apple1basic
>PRINT"HELLO WORLD!"
HELLO WORLD!
>

Now let’s write a small program:

$ apple1basic
>10 FOR I = 1 TO 10
>20 TAB I: PRINT "HELLO WORLD!"
>30 NEXT I
>40 END
>RUN
HELLO WORLD!
 HELLO WORLD!
  HELLO WORLD!
   HELLO WORLD!
    HELLO WORLD!
     HELLO WORLD!
      HELLO WORLD!
       HELLO WORLD!
        HELLO WORLD!
         HELLO WORLD!
>

We can tell apple1basic to run a BASIC program from a file, too:

$ cat hello.bas
10 FOR I = 1 TO 10
20 TAB I: PRINT "HELLO WORLD!"
30 NEXT I
40 END
$ apple1basic hello.bas
HELLO WORLD!
 HELLO WORLD!
  HELLO WORLD!
   HELLO WORLD!
    HELLO WORLD!
     HELLO WORLD!
      HELLO WORLD!
       HELLO WORLD!
        HELLO WORLD!
         HELLO WORLD!
$

apple1basic can be interactive:

$ cat name.bas
10 DIM N$(20)
20 PRINT "WHAT IS YOUR NAME";
30 INPUT N$
40 PRINT "HELLO, "; N$; "!"
50 END
$ apple1basic name.bas
WHAT IS YOUR NAME?MICHAEL
HELLO, MICHAEL!
$

apple1basic supports redirection of stdin and stdout. Note that if stdin is a pipe, “INPUT” doesn’t print the “?”:

$ cat reverse.bas
10 DIM A$(100)
20 INPUT A$
30 FOR I = LEN(A$) TO 1 STEP -1
40 PRINT A$(I,I);
50 NEXT I
60 PRINT
70 END
$ echo MICHAEL STEIL | apple1basic reverse.bas
LIETS LEAHCIM
$

Which brings us back to our first example: You can even use apple1basic as a UNIX script interpreter by adding the hashbang as the first line:

$ cat reverse.bas
#!/usr/bin/apple1basic
10 DIM A$(100)
20 INPUT A$
30 FOR I = LEN(A$) TO 1 STEP -1
40 PRINT A$(I,I);
50 NEXT I
60 END
$ chmod a+x reverse.bas
$ echo MICHAEL STEIL | ./reverse.bas
LIETS LEAHCIM
$

Some more programs

These games, written for the Apple I in the 1970s, have been taken from this and other sites and converted from tokenized hexcode into ASCII.

You can also download hanoi-apple1.bas, a fixed version of Amit Singh’s BASIC program from his Hanoimania project.

How it is done

My static recompiler takes the Apple I BASIC binary as an input and produces a native executable. This file does not contain the original 6502 code and runs 100% natively. On a 2 GHz machine, it runs about 2000 times faster than a 1 MHz Apple I, so it can run one 6502 clock cycle per native cycle. (In the best case, an interpreter can only get up to 1/10 of an emulated cycle per native cycle.)

Accesses to the Apple I terminal (keyboard and screen) are handled by functions that implement a few hacks. Depending on the program counter and the stack, I can discard some output (like terminal echo, 80 column forced line wrap) and redirect files and stdin to keyboard input, depending on context. For example, if there is a filename on the command line, keyboard emulation passes these characters into BASIC, and adds the “RUN” command. All following input will be read from stdin, and as soon as the code to print the “>” prompt is detected, the output handler quits the application.

Commodore BASIC / Microsoft BASIC 6502

I have done the same thing to the 9 KB Microsoft BASIC for 6502 taken from the Commodore 64 ROM.

cbmbasic_osx.zip

$ cbmbasic

    **** COMMODORE 64 BASIC V2 ****

 64K RAM SYSTEM  38911 BASIC BYTES FREE

READY.
_

It has many of the same features as Apple I BASIC: It discards the banner and the “READY.” prompt output when runnig in non-interactive mode, accepts a BASIC file as a parameter, and can be used as a script interpreter.

But… why??

I love the idea of reusing old code. Emulation is nice, but it rarely integrates well into modern systems. Most code out there has either a very lightweight (or well-understood) interface to the hardware (like the Apple I) or the opertaing system (like Commodore BASIC, as well as all programs from the GUI era), so hooking it up with modern operting system services can work out very nicely.

Also, emulation of vintage systems rarely cares too much about performance any more, since it is usually fast enough, i.e. as fast as or faster than the original system. But computers have always been slow, and running very old code can have the advantage of working with really fast software.

And yes, I think there is a lot of useful vintage code out there.

Links

57 thoughts on “Apple I BASIC as a Mac OS X Scripting Language”

  1. When I tried copying this to my /usr/local/bin & running it I got the following error message:

    -bash: /usr/local/bin/apple1basic: cannot execute binary file

    I am running Mac OS X 10.4.11. Does this program only work on 10.5?

  2. @Evan: The binaries posted are Intel-only for now, sorry. If you ask nicely, I’ll target PowerPC, too. :-)

  3. Very cool! I’d love to have it under Linux. Is it opensourced or do you have any plan on porting it to Linux? Indeed, very well done!

  4. hah what a brilliant idea, just makes me wish I could actually understand basic to be able to make something cool with it

  5. Nice thesis – please add me to the list of people asking nicely for source code.

    Remember, this whole thing (Apple) started by taking advantage of Woz’ willingness to share.
    It’s only fair to make your ‘Apple I BASIC interpreter’ available in source, so those of us who
    run Linux or PowerPC processors can benefit.

    Other folks wrote “open letters” to people who shared their BASIC interpreters.

    – Ralph

  6. The random number generator isn’t seeded differently per run, so you always get the same values. How did it work on the original hardware?

    ] cat random.bas
    #!/usr/bin/env apple1basic
    10 FOR I=1 TO 100
    20 PRINT RND(100);” “;
    30 NEXT I
    40 PRINT
    50 END
    ]
    ] ./random.bas
    56 72 81 92 2 80 60 31 56 80 68 7 43 20 48 4 49 94 60 54 20 2 79 4 35 22 26 16 36 32 41 82 1 36 30 11 8 59 85 24 34 29 28 24 21 1 39 30 56 28 48 42 97 65 75 15 73 76 41 12 52 12 69 43 91 99 40 67 59 94 69 57 9 34 92 56 61 84 34 77 35 6 14 7 68 83 44 26 2 28 81 13 72 75 7 36 30 59 47 50
    ]
    ] ./random.bas
    56 72 81 92 2 80 60 31 56 80 68 7 43 20 48 4 49 94 60 54 20 2 79 4 35 22 26 16 36 32 41 82 1 36 30 11 8 59 85 24 34 29 28 24 21 1 39 30 56 28 48 42 97 65 75 15 73 76 41 12 52 12 69 43 91 99 40 67 59 94 69 57 9 34 92 56 61 84 34 77 35 6 14 7 68 83 44 26 2 28 81 13 72 75 7 36 30 59 47 50

  7. Hello ! I love Basic, I used ZX Spectrum, Commodore 64, PC XT, 286,386,486,P1,PII,PIII and P4 lots of Basics, GWBasic,QBasic, Visual Basic 1,4,6 and .NET and now Real Basic on My Power Mac G4@1.5 Ghz.
    I need to use this script basic for PPC (becouse I love my Mac)and I want to make some script for it !! please ! if you will make some ppc versions please send me an E-mail.

  8. This brings back some old and SCARY memories of programming PDP 11/45’s back in the 1970’s.

  9. +1 for a PPC port … please!

    BTW, my Dad has a very old gwbasic script that he wants me to update. Will this apple1basic run a gwbasic script? Or am I comparing apples to oranges?

    :-)
    sjs

  10. I love it. Are you generating assembly or using some intermediate representation like C? How portable would the resulting code be? Since you’re using POSIX IO, could you easily emit code for other IA32 (or amd64) POSIX systems or even portably for all POSIX systems? I’d love to run these, but am not a Mac user.

  11. The ‘apple1basic’ program works fine, everything works as it should, as a script, and non-interactively. But, for some reason, the cbmbasic program only works interactively. When I try to run it as part of a script, it simply does nothing.

    I’d love to have the source for this.

    Then again, cbm basic for the C=64 is well documented. It seems like it should not be too hard for a good ‘c’ programmer to just write an implementation that would be portable.

  12. Wow! This is an awesome idea. Commore 64 was my first computer and I loved it. I used to write quite a few simple programs on it. Let’s PEEK, POKE, and SYS

  13. Is there any chance of the Apple BASIC being ported to windows, like cbmbasic was? It rocks!

  14. >>But? why??

    Why? Because it’s completely awesome! That’s why!

    As a guy who cut his teeth on the Apple ][, spending thousands of hours learning every inch of that wonderful machine, typing in programs from Nibble magazine (and those Beagle Bros. 2-line obfuscated gems), I can’t thank you enough for this.

    This makes me smile.

  15. Like Jack… I’m just glad someone did this… for both Apple and c64 no less! Double Awesome!

    I wonder how the c64 POKE and PEEK commands work out now? Integrated into the OS hardware? Can I “emulate” the SID chip? LOL…

  16. To Mark Hughes: (Random number generator question…)

    I used to own an Apple II — random numbers were always in the same pattern everytime the computer was booted. Turn on the computer on a given day, select a series of random numbers. Turn off the computer, then restart the computer — select a series of random numbers again… same series of numbers as before. So, I’m pretty sure random numbers were generated based on the internal clock from the moment the computer was swicthed on.

  17. How do I create a new file called hello.bas for me to cat. Please excuse my naivette.
    I installed the binary in the correct /usr/bin and was able to run the hello world operations from the prompt. When I try to do the example command “cat hello.bas” I get an error that the file doesn’t exist.

  18. @Michael Steil:
    Your smiley face leads me to believe you are trying to be helpful, but I ask in all sincerity “Did you try creating a .bas file with TextEdit before you recommended it?”
    -No, probably not. Because as far as I can tell you can’t create a .bas file with text edit.

    On a positive note your comment inspired me to try gedit which worked perfectly.

    Thanks for the bump over that hurdle.

  19. After further investigation into the preferences of TextEdit I found that by changing the New Document / Format setting to Plain Text I am able to save a ‘.bas’ file.

    Sorry, if my reply came across as snarky.

    I am still thankful for your reply which sent me down this road.

  20. @Mark Hughes and @BillBoard:

    I don’t know how apple I basic did, but the Microsoft basic used in C64, VIC-20 e.t.c. always gave the same random series every time you powered on / reset’ed the computer.

    I remember that the RND function took a negative parameter to initiate the random generator to a specific random series (i.e. you could specify a specific gamle run for games using random numbers by initiating the random number generator with a specific negative numer – compare to freecell.exe – “choose game#” in most windows versions), and most programs started with something like
    10 X = RND (-TI)
    where X were discarded and TI were the real time clock with 60Hz resolution. Because it’s highly unlikely that you start a program on exactly the same clock tick twice it gives a good enough variation.

    AFAIK the random number was however not that good if it were initialized with a rather high negative numer, so if the computer had been running for a few hours or you had set the real time clock yourself (with for example TI$=”101112″ for 12 seconds past 10:11 AM) you could get really bad random series which repeated very fast.

    Try a program like
    10 A=RND(-65530)
    20 A=RND(1)
    30 I=I+1
    40 B=RND(1)
    50 PRINT B;
    60 IF BA THEN 30
    70 PRINT “R:”;I;
    80 I=0
    90 GET A$
    100 IF A$=”X” THEN END
    110 IF A$=” ” THEN 30
    120 GOTO 90

    that program will initialize the random number generator, generate a number and then keep on generating numbers and print them until it encounders the same number again, then wait for “X” for exit or space to continue, that way you can look at the sceen and check for repeating patterns yourself.

    (I haven’t tried the program myself, it may contain errors. Also I don’t remember if the maximum initialization number were around -32768 or -65535, AFAIK higher numbers were truncated)

  21. Hi, i’ve got the binary for windows (xp). Is giving me all kinds of syntax error messages. I’ve got the vcredistrib installed so i’m clueless why this is not working for me. Frustrating because in many ways it works and i start to get excited. I have other versions of MBasic that work flawlessly so i’m not sure where to start. Checksums?

  22. Michael, just checking back and i see that a message that i thought i posted before is not here. So here goes again…

    Upper case doesn’t solve the problem. I can do something simple like:

    10 Print “Hello”
    Run
    But beyond this, not much. Even in caps, i can’t LIST or CLS and other basic commands without “syntax errors”. I am reminded of a time when i got the binary for the MESS project and it didn’t work. So finally, in frustration, i downloaded the SVN file, which was huge, and compiled it. Finally I was able to get a working version. I wonder if this is the same situation. Meanwhile, i have a question for anyone. Is this version of the BASIC interpreter for the Commodore true to it’s original function? Is it a robust rendition of the original? I am interested in programming somthing that will run on top of it and need it to be reliable. Anyone?

  23. Ok, partly, the problem is i was unfamiliar with the version of BASIC that came with the Commodore 64. I had been recently using IBM PC BASIC from era 1982 and assumed there were more similarities than there were. For one thing, 10 Print “Hello” won’t work in C64 BASIC because PRINT needs to be capitalized, even in a line. Once i googled and downloaded some original documentation, i was having much better luck with CBM BASIC. It’s complicated though, because i’m still getting two situations where it does not seem to function right. When calling on a time function such as TI or TI$, my DOS window shuts down immediately. Also, i get extra characters on the screen when printing numbers and spaces. I’m running XP on a Pentium 3. Dunno.

  24. Thank you. I’ve been looking for a basic interpreter for the Mac command line for a while now, and this is my solution (and a darn good one too!)

  25. IT looks great. for basic learner. there are alternative basic program in mac. ‘ object-basic’ tool which does not look comfortable [ as normal users in window programming pattern ] only syntax except dialog I supposed..

  26. hello, like john i’m receiving syntax error messages consistently. the .exec file opens in terminal, and i have no previous familiarity with basic at all. i am using a macbook OS X ver. 10.6.8. I have no previous experience with coding or writing programs, and thought going all the way back to the “beginning” would help me out as my main goal is to program arcade games in the original approach. in any event, i downloaded the user manual, and i’ve even tried following some online instructionals but everything returns a syntax error except for “hello world!”. i am even unable to copy the apple1basic to /usr/bin. any help would be greatly appreciated. thank you.

  27. I am new to the terminal. How do you exit the ‘>’ prompt area. Is it something that is a bash thing. I tried “bye” which I thought I remembered from Applesoft basic, but it didn’t work. Also how is this basic different from Apple Integer BASIC or is it the same thing?

  28. Hi,

    How Wonderful!

    But, I cannot get many of the Numeric Commands to work, like INT(), EXP(), or LOG().

    Is there more to the installation than I have done?

    Please advise.

    Thanks,

    Dave

  29. I would love to use this to do some BASIC scripting instead of learning Perl for a simple task, but when I try to copy it to /usr/bin I get:
    sudo cp apple1basic /usr/bin
    Password:
    cp: /usr/bin/apple1basic: Operation not permitted

    And when I try to run it directly from the local directory I get a different error:
    ./apple1basic
    zsh: bad CPU type in executable: ./apple1basic

  30. Hello,

    I would live to have it available on M1 too, would be awsome and will continue to show younger generation ;-)

Leave a Reply to Alex SchrĂśder Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.