Tiny BASIC is a version of BASIC written in Run BASIC. It was originally written by Laurent DUVEAU and is ported from iziBasic to Run BASIC by Carl Gundel and Scott McLaughlin. The beautiful thing about this interpreter is that it is so small. Without too much difficulty it can be understood and extended.

Here are some ideas for projects:
  • add graphics
  • add an HTML command like Run BASIC has
  • add string variables
  • add GOSUB and RETURN
  • port Tiny BASIC to your favorite language (Liberty BASIC perhaps?)

We strongly recommend you also check out http://www.aldweb.com/ and also Wikipedia's entry on Tiny BASIC at http://en.wikipedia.org/wiki/Tiny_Basic

Note: There is some code below that is commented out. It should be fairly self evident what this code used to do. It is left as an exercise to the reader to make it work if so inclined. ;-)

Enjoy!
    'tinyBasic.iBas
    ' ---
    ' tinyBasic v1.0
    ' Copyleft 2005 by Laurent DUVEAU
    ' http://www.aldweb.com/
    ' an iziBasic sample program
    ' Ported to Liberty BASIC by Carl Gundel
    ' and Scott McLaughlin
    ' [[http://www.libertybasic.com/|http://www.libertybasic.com]]
    ' ---
    ' A temp
    ' B temp
    ' C character index in line
    ' E line number for error msg
    ' I temp (loops)
    ' L number of lines
    ' N number
    ' S expression stack index
    ' T temp
    ' V variable index
    ' A$ temp
    ' B$ temp
    ' C$ character
    ' D$ single statement
    ' E$ error message
    ' G$ string code (")
    ' H$ HALT code (Line Feed)
    ' I$-R$ Help
    ' Z$=A$(26) statement input
    DIM A$(125) ' [27-125] = 99 program lines
    DIM A(82) ' [27-52] = 26 variables
    ' [53-82] = 30 items math stack
    A$(9)="BYE, CLEAR, CLS, END"
    A$(10)="HELP, MEM, NEW, RUN"
    A$(11)="GOTO | LOAD | SAVE <exp>"
    A$(12)="IF <exp> THEN <statement>"
    A$(13)="INPUT <var>"
    A$(14)="[LET] <var>=<exp>"
    A$(15)="LIST [<exp>|PAUSE]"
    A$(16)="PRINT <exp|str>[,<exp|str>][;]"
    A$(17)="REM <any>"
    TRUE = 1
    FALSE = 0
    'BEGIN
    G$=CHR$(34) : H$=CHR$(10)
    ' B=FILEEXISTS("tinyBas0")
    ' IF B=TRUE THEN
    ' Z$="load0:run"
    ' GOTO _AutoRun
    ' END IF
[Ready]
    IF E$<>"" THEN
        IF E>0 THEN
            E$="#Err in "+STR$(E)+": "+E$
        ELSE
            E$="#Err: "+E$
        END IF
        PRINT E$ : E$=""
    END IF
    PRINT "Ready"
[Input]
    LINE INPUT Z$
    A$(26)=Z$
[AutoRun]
    L=26 : C=1 : GOSUB [GetNumber] : E=N
    IF N=0 THEN
        IF C$="" THEN [Ready]
        GOTO [NextStatement]
    ELSE
        GOSUB [EnterLine]
        IF E$<>"" THEN [Ready]
        GOTO [Input]
    END IF
[Exec]
    GOSUB [GetNumber] : E=N
[NextStatement]
    'A$=INKEY$
    'IF A$=H$ THEN
    '    A$="Break in "+STR$(E,0)
    '    PRINT A$ : GOTO [Ready
    'END IF
    GOSUB [GetLabel]
    IF E$<>"" THEN [Ready]
    SELECT CASE D$
        CASE "if"
        GOSUB [GetExpression]
        IF E$<>"" THEN [Ready]
        IF N<1 THEN
            B$=A$(L) : C=LEN(B$)+1
            GOTO [FinishStatement]
        END IF
        GOSUB [GetLabel]
        IF E$<>"" THEN [Ready]
        IF D$<>"then" THEN
            E$="'THEN' expected"
            GOTO [Ready]
        END IF
        GOTO [NextStatement]
        CASE "rem"
        B$=A$(L) : C=LEN(B$)+1
        GOTO [FinishStatement]
        CASE "input"
        GOSUB [GetVar]
        IF E$<>"" THEN [Ready]
        INPUT N : A(V)=N
        GOTO [FinishStatement]
        CASE "print"
[Print]
        GOSUB [SkipSpace]
        GOSUB [GetChar]
        IF C$=G$ THEN
            B$=""
[NextChar]
            C=C + 1 : C$=MID$(A$,C,1)
            IF C$="" THEN
                E$="Unterminated string"
                GOTO [Ready]
            ELSE
                IF C$<>G$ THEN
                    B$=B$+C$
                    GOTO [NextChar]
                END IF
            END IF
            C=C + 1 : C$=MID$(A$,C,1)
            IF C$=G$ THEN
                B$=B$+C$
                GOTO [NextChar]
            END IF
            PRINT B$;
        ELSE
            GOSUB [GetExpression]
            IF E$<>"" THEN [Ready]
            B=N1
            IF B=N THEN
                PRINT N;"*";
            ELSE
                PRINT N;
            END IF
        END IF
        GOSUB [SkipSpace]
        GOSUB [GetChar]
        IF C$="," THEN C = C + 1 : GOTO [Print]
        GOSUB [SkipSpace]
        GOSUB [GetChar]
        IF C$<>";" THEN
            PRINT
        ELSE
            C = C + 1
        END IF
        GOTO [FinishStatement]
        CASE "clear"
        FOR I=27 TO 52 : A(I)=0 : NEXT I
        GOTO [FinishStatement]
        CASE "run"
        FOR I=27 TO 52 : A(I)=0 : NEXT I
        L=27 : C=1
        GOTO [FinishStatement2]
        CASE "goto"
        GOSUB [GetExpression]
        IF E$<>"" THEN [Ready]
        IF E>=N THEN L=27
        C=1 : T=N
[NextGoto]
        IF L=126 THEN
            E$="Line not found"
            GOTO [Ready]
        END IF
        GOSUB [GetNumber]
        IF N=T THEN E=N : GOTO [NextStatement]
        L=L + 1 : C=1
        GOTO [NextGoto]
        CASE "new"
        FOR I=27 TO 125 : A$(I)="" : NEXT I
        FOR I=27 TO 52 : A(I)=0 : NEXT I
        IF E=0 THEN [FinishStatement]
        GOTO [Ready]
        CASE "cls"
        CLS : GOTO [FinishStatement]
        CASE "help"
        FOR I=9 TO 18
            B$=A$(I) : PRINT B$
        NEXT I
        GOTO [FinishStatement]
        CASE "mem"
        B=126
        FOR I=27 TO 125
            diffI = 152 - I 'Cheating here
            B$=A$(diffI) : IF B$="" THEN B=diffI
        NEXT I
        B=126-B : PRINT B;"*";
        PRINT " lines free"
        GOTO [FinishStatement]
        CASE "end"
        GOTO [Ready]
        CASE "bye"
        GOTO [ExitTinyBAS]
        CASE "list"
        GOSUB [GetNumber] : T=N : A=L : I=C
        IF T=0 THEN
            GOSUB [GetLabel]
            IF E$="" AND D$="pause" THEN I=C
            E$=""
        END IF
        FOR L=27 TO 125
            C=1 : GOSUB [GetNumber]
            B=(T=0) OR (N=T)
            IF B=TRUE THEN
                IF A$<>"" THEN
                    PRINT A$
                    IF D$="pause" THEN
                        B = (L-26) mod 10
                        IF B=0 THEN PRINT "Pause..."; : INPUT AAA$
                    END IF
                END IF
            END IF
        NEXT L
        L=A : C=I
        GOTO [FinishStatement]
        CASE "save"
        PRINT "SAVE, TBD"
        ' GOSUB [GetExpression]
        ' IF E$<>"" THEN [Ready]
        ' A$="tinyBas"+STR$(N) : A=FALSE
        ' OPEN A$ FOR OUTPUT AS #1
        ' FOR I=27 TO 125
        ' B$=A$(I)
        ' IF B$<>"" THEN PRINT #1,B$ : A=TRUE
        ' NEXT I
        ' CLOSE #1
        ' IF A=FALSE THEN KILL A$
        ' GOTO [FinishStatement]
        CASE "load"
        PRINT "LOAD, TBD"
        ' GOSUB [GetExpression]
        ' IF E$<>"" GOTO [Ready]
        ' A$="tinyBas"+STR$(N,0)
        ' B=FILEEXISTS(A$)
        ' IF B=FALSE THEN
        ' E$="File "+A$+" not found"
        ' GOTO [Ready]
        ' END IF
        ' OPEN A$ FOR INPUT AS #1
        ' B=FALSE : I=27
        ' WHILE B=FALSE
        ' B=EOF(#1)
        ' INPUT #1,B$ : A$(I)=B$ : I=I+1
        ' WEND
        ' CLOSE #1
        ' WHILE I<=125
        ' A$(I)="" : I=I+1
        ' WEND
        ' IF E=0 THEN [FinishStatement]
        ' GOTO [Ready]
        CASE "let"
        GOSUB [GetLabel]
        IF E$<>"" THEN [Ready]
    END SELECT
    GOSUB [ReturnVar]
    IF E$<>"" THEN [Ready]
    GOSUB [SkipSpace]
    GOSUB [GetChar]
    IF C$<>"=" THEN
        E$="'=' expected"
        GOTO [Ready]
    END IF
    C=C + 1 : T=V
    GOSUB [GetExpression]
    IF E$<>"" THEN [Ready]
    A(T)=N
[FinishStatement]
    GOSUB [SkipSpace]
    GOSUB [GetChar]
    IF C$=":" THEN
        C = C + 1 : GOTO [NextStatement]
    ELSE
        IF C$<>"" THEN
            E$="End of statement expected"
            GOTO [Ready]
        END IF
    END IF
    IF L=26 THEN [Ready]
    L=L + 1 : C=1
    IF L=126 THEN
        E$="Program Overflow"
        GOTO [Ready]
    END IF
[FinishStatement2]
    B$=A$(L)
    IF B$="" THEN [Ready]
    GOTO [Exec]
[ExitTinyBAS]
    PRINT "Thanks for using Tiny BASIC."
    END
[EnterLine]
    L=27 : C=1 : T=N
[NextLine]
    GOSUB [GetNumber]
    B=(N<T) AND (N<>0) AND (L<126)
    IF B=TRUE THEN
        L=L + 1 : C=1 : GOTO [NextLine]
    END IF
    IF L=126 THEN
        E$="Program Overflow"
        GOTO [EndEnterLine]
    END IF
    IF T<>N THEN
        FOR I=L to 125
            diffI = (125+L)-I
            B=diffI-1 : A$(diffI)=A$(B)
        NEXT I
    END IF
    A$(L)=Z$
    GOSUB [SkipSpace]
    IF C$="" THEN
        FOR I=L TO 124
            B=I+1 : A$(I)=A$(B)
        NEXT I
    END IF
[EndEnterLine]
    RETURN
[GetExpression]
    A(53)=0 : S=53
    GOSUB [BoolExpression]
    N=A(S) : GOTO [EndExpression]
[BoolExpression]
    GOSUB [AddExpression]
    GOSUB [SkipSpace]
    GOSUB [GetChar]
[NextBool]
    SELECT CASE C$
        CASE "="
        C = C + 1 : GOSUB [AddExpression]
        B=S-1 : A(B)=A(B)=A(S) : S = S - 1
        CASE ">"
        C = C + 1 : GOSUB [GetChar]
        IF C$="=" THEN
            C = C + 1 : GOSUB [AddExpression]
            B=S-1 : A(B)=A(B)>=A(S) : S = S - 1
        ELSE
            GOSUB [AddExpression]
            B=S-1 : A(B)=A(B)>A(S) : S = S - 1
        END IF
        CASE "<"
        C = C + 1 : GOSUB [GetChar]
        SELECT CASE C$
            CASE "="
            C = C + 1 : GOSUB [AddExpression]
            B=S-1 : A(B)=A(B)<=A(S) : S = S - 1
            CASE ">"
            C = C + 1 : GOSUB [AddExpression]
            B=S-1 : A(B)=A(B)<>A(S) : S = S - 1
            CASE ELSE
            GOSUB [AddExpression]
            B=S-1 : A(B)=A(B)<A(S) : S = S - 1
        END SELECT
    END SELECT
    GOSUB [SkipSpace]
    GOSUB [GetChar]
    B=ASC(C$) : B=(B>=60) AND (B<=62)
    IF B=TRUE THEN [NextBool]
    GOTO [EndExpression]
[AddExpression]
    GOSUB [MulExpression]
    GOSUB [SkipSpace]
    GOSUB [GetChar]
[NextAdd]
    SELECT CASE C$
        CASE "+"
        C = C + 1 : GOSUB [MulExpression]
        B=S-1 : A(B)=A(B)+A(S) : S = S - 1
        CASE "-"
        C = C + 1 : GOSUB [MulExpression]
        B=S-1 : A(B)=A(B)-A(S) : S = S - 1
    END SELECT
    GOSUB [SkipSpace]
    GOSUB [GetChar]
    B=ASC(C$) : B=(B=43) OR (B=45)
    IF B=TRUE THEN [NextAdd]
    GOTO [EndExpression]
[MulExpression]
    GOSUB [GroupExpression]
    GOSUB [SkipSpace]
    GOSUB [GetChar]
[NextMul]
    SELECT CASE C$
        CASE "*"
        C = C + 1 : GOSUB [GroupExpression]
        B=S-1 : A(B)=A(B)*A(S) : S = S - 1
        CASE "/"
        C = C + 1 : GOSUB [GroupExpression]
        B=A(S)
        IF B=0 THEN
            IF E$="" THEN E$="Division by zero"
            S = S - 1 : GOTO [EndExpression]
        ELSE
            B=S-1 : A(B)=A(B)/A(S) : S = S - 1
        END IF
        CASE " "
        C = C + 1 : GOSUB [GroupExpression]
        B=A(S)
        IF B=0 THEN
            IF E$="" THEN E$="Division by zero"
            S = S - 1 : GOTO [EndExpression]
        ELSE
            B=S-1 : A(B)=A(B) mod A(S) : S = S - 1
        END IF
    END SELECT
    GOSUB [SkipSpace]
    GOSUB [GetChar]
    B=ASC(C$)
    B=(B=42) OR (B=47) OR (B=92)
    IF B=TRUE THEN [NextMul]
    GOTO [EndExpression]
[GroupExpression]
    GOSUB [SkipSpace]
    GOSUB [GetChar]
    SELECT CASE C$
        CASE "("
        C = C + 1 : GOSUB [BoolExpression]
        GOSUB [SkipSpace]
        GOSUB [GetChar]
        IF C$<>")" THEN
            IF E$="" THEN E$="Missing ')'"
            GOTO [EndExpression]
        END IF
        C = C + 1
        CASE ""
        IF E$="" THEN E$="Invalid Factor"
        CASE ELSE
        B=ASC(C$) : B=(B<48) OR (B>57)
        IF B=FALSE THEN
            GOSUB [GetNumber]
            S=S + 1 : A(S)=N
        ELSE
            GOSUB [GetLabel]
            IF E$<>"" THEN [EndExpression]
            B=LEN(D$)
            IF B=1 THEN
                GOSUB [ReturnVar]
                S=S + 1 : A(S)=A(V)
            ELSE
                SELECT CASE D$
                    CASE "ticks"
                    S=S + 1 : A(S)=TICKS
                    CASE "tickspersec"
                    S=S + 1 : A(S)=TICKSPERSEC
                    CASE ELSE
                    IF E$="" THEN E$="Function expected"
                END SELECT
            END IF
        END IF
    END SELECT
[EndExpression]
    RETURN
[GetNumber]
    GOSUB [SkipSpace]
    B$=""
[NextNumber]
    GOSUB [GetChar]
    IF C$="" THEN [GetNumberExit]
    B=ASC(C$)
    B=((B<48) OR (B>57)) AND (B<>46)
    IF B=TRUE THEN [GetNumberExit]
    B$=B$+C$ : C = C + 1 : GOTO [NextNumber]
[GetNumberExit]
    N=VAL(B$)
    RETURN
[GetVar]
    GOSUB [GetLabel]
    IF E$<>"" THEN [GetVarExit]
[ReturnVar]
    B=ASC(D$) : A=LEN(D$)
    A=(A<>1) OR (B<97) OR (B>122)
    IF A=FALSE THEN
        V=B-70
    ELSE
        IF E$="" THEN E$="Variable expected"
    END IF
[GetVarExit]
    RETURN
[GetLabel]
    GOSUB [SkipSpace]
    GOSUB [GetChar]
    D$=""
    IF C$="" THEN [GetLabelError]
    B=ASC(C$) : B=(B<97) OR (B>122)
    IF B=TRUE THEN [GetLabelError]
[GetNextLabel]
    D$=D$+C$ : C = C + 1
    GOSUB [GetChar]
    IF C$="" THEN [GetLabelExit]
    B=ASC(C$) : B=(B>=97) AND (B<=122)
    IF B=TRUE THEN [GetNextLabel]
    GOTO [GetLabelExit]
[GetLabelError]
    IF E$="" THEN E$="Invalid label"
[GetLabelExit]
    RETURN
[SkipSpace]
    GOSUB [GetChar]
    IF C$=" " THEN C = C + 1 : GOTO [SkipSpace]
    RETURN
[GetChar]
    A$=A$(L)
    C$=MID$(A$,C,1) : C$=LOWER$(C$)
    RETURN