Information Technology - Computer Programming - Source Code - Homebrew - Open Source - Software - Hardware - 8 bit - 16 bit - 32 bit - 64 bit - x86 - x64 - DOS - Windows - Linux - Arduino - Embedded - Development - Retro - Vintage - Math - Science - History - Hobby - Beginners - Professionals - Experiment - Research - Study - Fun - Games

Tiny BASIC Example

Share your Express Basic creations here.
Post Reply
admin
Site Admin
Posts: 129
Joined: Wed Feb 22, 2023 6:51 am

Tiny BASIC Example

Post by admin »

Tiny BASIC Example

Statements:

IF expression THEN linenumber
LET variable = expression
PRINT expression
PRINT "quoted text"
INPUT variable
GOTO linenumber
REM
END
CLS

Functions:

ABS()
INT()

Operator Precedence:

NOT()
^ MOD
* /
+ -
< > <= >=
= <>
XOR
AND
OR

Variables:

26 available named A-Z

Notes:

One statement per line is allowed. Supports negation and decimal values.
Line numbers are tied to memory (for simplicity) so the maximum lines that
may be separated by 10 are 25 with more lines between up to 256 total.

About:

The purpose of this toy interpreter is to demonstrate Express BASIC string
operations. It could use a lot of improvement to be more useful and is
honestly too slow to be useful when ran from Express BASIC.

Expression evaluation is done using RPN.

It will run decently fast with the DPMI, Windows, and Linux editions, but
is super slow on DOS. Try porting it to run on QBasic or your favorite
compiler/interpreter.

Porting it to QBasic is as simple as changing the @ and $ arrays to A and S$
while also accounting for any NOT operations which differ between QBasic and
Express BASIC. QBasic uses boolean while Express BASIC uses logical.

There shouldn't be many other differences. Maybe change INPUT to LINE INPUT
for QBasic. Try making a few examples or better yet even adding a new command
or two!

Code: Select all

1 REM Tiny BASIc Example by Gemino Smothers
2 REM Written in Express BASIC
3 REM @(0-99) = evalstack @(100-125) = varvals $(0-255) = lines
5 CLS: PRINT "Tiny BASIC Example": PRINT
10 INPUT "*.BAS: ", filename$: OPEN "I", #1, filename$: IF EOF(1) THEN 70
20 INPUT #1, statement$: IF LEN(statement$) = 0 THEN 60
30 spacepos = INSTR(statement$, " "): IF spacepos THEN currentline = VAL(LEFT$(statement$, spacepos - 1)) - 1
40 statement$ = RIGHT$(statement$, LEN(statement$) - spacepos)
50 $(currentline) = statement$
60 IF EOF(1) = 0 THEN 20
70 CLOSE #1
80 GOSUB 19000: FOR currentline = 0 TO 255
90 GOSUB 20000: IF cmd$ <> "" THEN GOSUB 21000
100 NEXT currentline: END
10000 postfix$ = "": operatorstack$ = "": GOSUB 14000
10010 FOR symbolpos = 1 TO LEN(infix$)
10020 symbol$ = MID$(infix$, symbolpos, 1): IF symbol$ = " " THEN 10130
10030 IF symbol$ = "." OR (ASC(symbol$) >= 48 AND ASC(symbol$) <= 57) THEN postfix$ = postfix$ + symbol$: GOTO 10130
10040 IF ASC(symbol$) >= 65 AND ASC(symbol$) <= 90 THEN postfix$ = postfix$ + STR$(@(ASC(symbol$) + 35)): GOTO 10130
10050 IF symbol$ = "(" THEN operatorstack$ = operatorstack$ + symbol$: GOTO 10130
10060 IF symbol$ = ")" THEN GOSUB 11000: GOTO 10130
10070 IF symbol$ = "|" OR symbol$ = "&" OR symbol$ = "~" OR symbol$ = "=" THEN GOSUB 12000: GOTO 10130
10080 IF symbol$ = "#" OR symbol$ = "<" OR symbol$ = ">" OR symbol$ = "{" THEN GOSUB 12000: GOTO 10130
10090 IF symbol$ = "}" OR symbol$ = "+" OR symbol$ = "-" OR symbol$ = "*" THEN GOSUB 12000: GOTO 10130
10100 IF symbol$ = "/" OR symbol$ = "%" OR symbol$ = "^" OR symbol$ = "!" THEN GOSUB 12000: GOTO 10130
10110 IF symbol$ = CHR$(131) OR symbol$ = CHR$(132) THEN GOSUB 12000: GOTO 10130
10120 IF symbol$ = "_" THEN postfix$ = postfix$ + "-"
10130 NEXT symbolpos
10140 newstack$ = ""
10150 FOR symbolpos = 1 TO LEN(operatorstack$)
10160 newstack$ = newstack$ + " " + MID$(operatorstack$, symbolpos, 1)
10170 NEXT symbolpos
10180 operatorstack$ = newstack$
10190 postfix$ = postfix$ + operatorstack$
10200 GOSUB 15000: RETURN
11000 IF RIGHT$(operatorstack$, 1) = "(" THEN 11040
11010 postfix$ = postfix$ + " " + RIGHT$(operatorstack$, 1)
11020 operatorstack$ = LEFT$(operatorstack$, LEN(operatorstack$) - 1)
11030 IF RIGHT$(operatorstack$, 1) <> "(" THEN 11010
11040 operatorstack$ = LEFT$(operatorstack$, LEN(operatorstack$) - 1)
11050 RETURN
12000 GOSUB 13000
12010 IF LEN(operatorstack$) = 0 OR RIGHT$(operatorstack$, 1) = "(" OR symbolprecedence > stackprecedence THEN 12060
12020 postfix$ = postfix$ + " " + RIGHT$(operatorstack$, 1)
12030 operatorstack$ = LEFT$(operatorstack$, LEN(operatorstack$) - 1)
12040 GOSUB 13000
12050 IF LEN(operatorstack$) AND RIGHT$(operatorstack$, 1) <> "(" AND symbolprecedence <= stackprecedence THEN 12020
12060 operatorstack$ = operatorstack$ + symbol$
12070 postfix$ = postfix$ + " "
12080 RETURN
13000 stacktop$ = RIGHT$(operatorstack$, 1)
13010 IF stacktop$ = "|" THEN stackprecedence = 1: GOTO 13120
13020 IF stacktop$ = "&" THEN stackprecedence = 2: GOTO 13120
13030 IF stacktop$ = "~" THEN stackprecedence = 3: GOTO 13120
13040 IF stacktop$ = "=" OR stacktop$ = "#" THEN stackprecedence = 4: GOTO 13120
13050 IF stacktop$ = "<" OR stacktop$ = ">" THEN stackprecedence = 5: GOTO 13120
13060 IF stacktop$ = "<=" OR stacktop$ = ">=" THEN stackprecedence = 5: GOTO 13120
13070 IF stacktop$ = "+" OR stacktop$ = "-" THEN stackprecedence = 6: GOTO 13120
13080 IF stacktop$ = "*" OR stacktop$ = "/" THEN stackprecedence = 7: GOTO 13120
13090 IF stacktop$ = "%" OR stacktop$ = "^" THEN stackprecedence = 8: GOTO 13120
13100 IF stacktop$ = "!" THEN stackprecedence = 9: GOTO 13120
13110 stackprecedence = 0
13120 IF symbol$ = "|" THEN symbolprecedence = 1: GOTO 13230
13130 IF symbol$ = "&" THEN symbolprecedence = 2: GOTO 13230
13140 IF symbol$ = "~" THEN symbolprecedence = 3: GOTO 13230
13150 IF symbol$ = "=" OR symbol$ = "#" THEN symbolprecedence = 4: GOTO 13230
13160 IF symbol$ = "<" OR symbol$ = ">" THEN symbolprecedence = 5: GOTO 13230
13170 IF symbol$ = "<=" OR symbol$ = ">=" THEN symbolprecedence = 5: GOTO 13230
13180 IF symbol$ = "+" OR symbol$ = "-" THEN symbolprecedence = 6: GOTO 13230
13190 IF symbol$ = "*" OR symbol$ = "/" THEN symbolprecedence = 7: GOTO 13230
13200 IF symbol$ = "%" OR symbol$ = "^" THEN symbolprecedence = 8: GOTO 13230
13210 IF symbol$ = "!" THEN symbolprecedence = 9: GOTO 13230
13220 symbolprecedence = 0
13230 RETURN
14000 infix$ = "(" + infix$ + ")": IF LEN(infix$) = 3 THEN RETURN
14010 FOR replacesymbol = 1 TO LEN(infix$)
14020 IF INSTR(infix$, " OR ") = 0 THEN 14060
14030 leftfix$ = LEFT$(infix$, INSTR(infix$, " OR ")  - 1)
14040 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 4)
14050 infix$ = leftfix$ + "|" + infix$: GOTO 14340
14060 IF INSTR(infix$, " AND ") = 0 THEN 14100
14070 leftfix$ = LEFT$(infix$, INSTR(infix$, " AND ") - 1)
14080 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 5)
14090 infix$ = leftfix$ + "&" + infix$: GOTO 14340
14100 IF INSTR(infix$, " XOR ") = 0 THEN 14140
14110 leftfix$ = LEFT$(infix$, INSTR(infix$, " XOR ") - 1)
14120 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 5)
14130 infix$ = leftfix$ + "~" + infix$: GOTO 14340
14140 IF INSTR(infix$, " MOD ") = 0 THEN 14180
14150 leftfix$ = LEFT$(infix$, INSTR(infix$, " MOD ") - 1)
14160 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 5)
14170 infix$ = leftfix$ + "%" + infix$: GOTO 14340
14180 IF INSTR(infix$, "<>") = 0 THEN 14220
14190 leftfix$ = LEFT$(infix$, INSTR(infix$, "<>") - 1)
14200 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 2)
14210 infix$ = leftfix$ + "#" + infix$: GOTO 14340
14220 IF INSTR(infix$, "<=") = 0 THEN 14260
14230 leftfix$ = LEFT$(infix$, INSTR(infix$, "<=") - 1)
14240 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 2)
14250 infix$ = leftfix$ + "{" + infix$: GOTO 14340
14260 IF INSTR(infix$, ">=") = 0 THEN 14300
14270 leftfix$ = LEFT$(infix$, INSTR(infix$, ">=") - 1)
14280 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 2)
14290 infix$ = leftfix$ + "}" + infix$: GOTO 14340
14300 IF INSTR(infix$, "NOT(") = 0 THEN 14340
14310 leftfix$ = LEFT$(infix$, INSTR(infix$, "NOT(") - 1)
14320 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 4)
14330 infix$ = leftfix$ + "!(" + infix$
14340 IF INSTR(infix$, "ABS(") = 0 THEN 14380
14350 leftfix$ = LEFT$(infix$, INSTR(infix$, "ABS(") - 1)
14360 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 4)
14370 infix$ = leftfix$ + "(" + CHR$(131) + infix$
14380 IF INSTR(infix$, "INT(") = 0 THEN 14420
14390 leftfix$ = LEFT$(infix$, INSTR(infix$, "INT(") - 1)
14400 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 4)
14410 infix$ = leftfix$ + "(" + CHR$(132) + infix$
14420 NEXT replacesymbol
14430 FOR replacesymbol = 1 TO LEN(infix$)
14440 IF MID$(infix$, replacesymbol, 1) <> "-" THEN 14600
14450 symbol$ = MID$(infix$, replacesymbol - 1, 1)
14460 symbolpos = replacesymbol
14470 IF symbol$ <> " " THEN 14510
14480 symbolpos = symbolpos - 1
14490 symbol$ = MID$(infix$, symbolpos - 1, 1)
14500 IF symbol$ = " " THEN 14480
14510 negative = 0
14520 IF symbol$ = "(" OR symbol$ = "|" OR symbol$ = "&" OR symbol$ = "~" OR symbol$ = "=" THEN negative = 1
14530 IF symbol$ = "#" OR symbol$ = "<" OR symbol$ = ">" OR symbol$ = "{" OR symbol$ = "}" THEN negative = 1
14540 IF symbol$ = "+" OR symbol$ = "-" OR symbol$ = "*" OR symbol$ = "/" OR symbol$ = "%" THEN negative = 1
14550 IF symbol$ = "^" OR symbol$ = "!" THEN negative = 1
14560 IF negative = 0 THEN 14600
14570 leftfix$ = LEFT$(infix$, replacesymbol - 1)
14580 infix$ = RIGHT$(infix$, LEN(infix$) - LEN(leftfix$) - 1)
14590 infix$ = leftfix$ + "_1*" + infix$
14600 NEXT replacesymbol
14610 RETURN
15000 @(0) = 0: pointer = 0
15010 postfix$ = LTRIM$(postfix$): IF INSTR(postfix$, " ") = 0 THEN symbol$ = postfix$: postfix$ = "": GOTO 15030
15020 symbol$ = LEFT$(postfix$, INSTR(postfix$, " ") - 1): postfix$ = RIGHT$(postfix$, LEN(postfix$) - LEN(symbol$) - 1)
15030 leftsymbol$ = LEFT$(symbol$, 1)
15040 IF (leftsymbol$ = "." OR (ASC(leftsymbol$) >= 48 AND ASC(leftsymbol$) <= 57)) = 0 THEN 15060
15050 @(pointer) = VAL(symbol$): pointer = pointer + 1: GOTO 15140
15060 IF leftsymbol$ = "|" OR leftsymbol$ = "&" OR leftsymbol$ = "~" OR leftsymbol$ = "=" THEN GOSUB 17000: GOTO 15140
15070 IF leftsymbol$ = "#" OR leftsymbol$ = "<" OR leftsymbol$ = ">" OR leftsymbol$ = "{" THEN GOSUB 17000: GOTO 15140
15080 IF leftsymbol$ = "}" OR leftsymbol$ = "+" OR leftsymbol$ = "*" OR leftsymbol$ = "/" THEN GOSUB 17000: GOTO 15140
15090 IF leftsymbol$ = "%" OR leftsymbol$ = "^" THEN GOSUB 17000: GOTO 15140
15100 IF leftsymbol$ = CHR$(131) THEN pointer = pointer - 1: @(pointer) = ABS(@(pointer)): pointer = pointer + 1: GOTO 15140
15110 IF leftsymbol$ = CHR$(132) THEN pointer = pointer - 1: @(pointer) = INT(@(pointer)): pointer = pointer + 1: GOTO 15140
15120 IF leftsymbol$ = "-" THEN GOSUB 16000: GOTO 15140
15130 IF leftsymbol$ = "!" THEN pointer = pointer - 1: @(pointer) = NOT(@(pointer)): pointer = pointer + 1
15140 IF LEN(postfix$) THEN 15010
15150 RETURN
16000 IF LEN(symbol$) > 1 THEN 16050
16010 operator$ = symbol$
16020 pointer = pointer - 1: operand2 = @(pointer): @(pointer) = 0
16030 pointer = pointer - 1: operand1 = @(pointer): @(pointer) = 0
16040 GOSUB 18000: GOTO 16060
16050 @(pointer) = VAL(symbol$): pointer = pointer + 1
16060 RETURN
17000 operator$ = symbol$
17010 pointer = pointer - 1: operand2 = @(pointer): @(pointer) = 0
17020 pointer = pointer - 1: operand1 = @(pointer): @(pointer) = 0
17030 GOSUB 18000: RETURN
18000 IF operator$ = "|" THEN @(pointer) = operand1 OR operand2
18010 IF operator$ = "&" THEN @(pointer) = operand1 AND operand2
18020 IF operator$ = "~" THEN @(pointer) = operand1 XOR operand2
18030 IF operator$ = "=" THEN @(pointer) = operand1 = operand2
18040 IF operator$ = "#" THEN @(pointer) = operand1 <> operand2
18050 IF operator$ = "<" THEN @(pointer) = operand1 < operand2
18060 IF operator$ = ">" THEN @(pointer) = operand1 > operand2
18070 IF operator$ = "{" THEN @(pointer) = operand1 <= operand2
18080 IF operator$ = "}" THEN @(pointer) = operand1 >= operand2
18090 IF operator$ = "+" THEN @(pointer) = operand1 + operand2
18100 IF operator$ = "-" THEN @(pointer) = operand1 - operand2
18110 IF operator$ = "*" THEN @(pointer) = operand1 * operand2
18120 IF operator$ = "/" THEN @(pointer) = operand1 / operand2
18130 IF operator$ = "%" THEN @(pointer) = operand1 MOD operand2
18140 IF operator$ = "^" THEN @(pointer) = operand1 ^ operand2
18150 pointer = pointer + 1: RETURN
19000 FOR currentvariable = 0 TO 25
19020 @(currentvariable + 100) = 0
19030 NEXT currentvariable: RETURN
20000 statement$ = $(currentline): IF LEN(statement$) = 0 THEN cmd$ = "": param$ = "": RETURN
20010 IF (INSTR(statement$, " ") > 1) = 0 THEN 20050
20020 cmd$ = UCASE$(RTRIM$(LEFT$(statement$, INSTR(statement$, " ") - 1)))
20030 param$ = LTRIM$(MID$(statement$, INSTR(statement$, " ") + 1, LEN(statement$) - INSTR(statement$, " ")))
20040 RETURN
20050 cmd$ = UCASE$(statement$): param$ = ""
20060 RETURN
21000 IF cmd$ <> "IF" THEN 22000
21010 param$ = UCASE$(param$)
21030 infix$ = LEFT$(param$, INSTR(param$, " THEN ") - 1)
21040 param$ = RIGHT$(param$, LEN(param$) - LEN(infix$))
21050 param$ = RIGHT$(param$, LEN(param$) - 6)
21060 GOSUB 10000: IF @(0) THEN currentline = VAL(param$) - 2
21070 RETURN
22000 IF cmd$ <> "LET" THEN 23000
22010 param$ = UCASE$(param$): assop = INSTR(param$, "=")
22020 letvar$ = RTRIM$(LEFT$(param$, assop - 1))
22030 infix$ = LTRIM$(RIGHT$(param$, LEN(param$) - assop))
22040 GOSUB 10000: @(ASC(letvar$) + 35) = @(0)
22050 RETURN
23000 IF cmd$ <> "PRINT" THEN 24000
23010 IF INSTR(param$, CHR$(34)) THEN 23030
23020 infix$ = UCASE$(param$): GOSUB 10000: PRINT @(0): RETURN
23030 param$ = MID$(param$, 2, LEN(param$) - 2): PRINT param$
23040 RETURN
24000 IF cmd$ <> "INPUT" THEN 25000
24010 INPUT @(ASC(UCASE$(param$)) + 35)
24020 RETURN
25000 IF cmd$ <> "GOTO" THEN 26000
25010 currentline = VAL(param$) - 2
25020 RETURN
26000 IF cmd$ = "END" THEN END
26010 IF cmd$ = "REM" THEN RETURN
26020 IF cmd$ = "CLS" THEN CLS: RETURN
26030 PRINT "INVALID COMMAND ON LINE #: "; currentline + 1: END
test program:

Code: Select all

10 REM test program
15 PRINT "Hello, world!"
20 INPUT n
30 PRINT i
40 LET i = i + 1
50 IF i < n THEN 30
60 PRINT 2 + 10 / 2
70 PRINT 2 + 10 / 2 = 7
80 PRINT 2 + 10 / 2 <> 7
90 PRINT NOT(0)
100 PRINT NOT(1)
110 PRINT 10/3+2
120 PRINT INT(10/3) + 2
130 END
Post Reply