Tiny+BASIC

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! code format="vbnet" '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] ' ---   ' 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 "    A$(12)="IF THEN "    A$(13)="INPUT "    A$(14)="[LET] = "    A$(15)="LIST [ |PAUSE]"    A$(16)="PRINT [,][;]"    A$(17)="REM "    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=(N0) 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)=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 code