Express BASIC - an interpreter in C

Started by Lucidapogee, Oct 17, 2023, 06:03 AM

Previous topic - Next topic

Lucidapogee

Express BASIC is a minimal BASIC dialect that is suitable for performing complex calculations. The language is inspired by Dartmouth, Palo Alto, Altair, GW BASIC, and the many dialects of Tiny BASIC.

It is written in mostly C and is open source. I have been working nonstop on this and am finally at a point I am comfortable sharing it. The syntax is very close to Net Basic. Most programs written in Express BASIC will run in QBasic or GWBasic with little modification.

Programs may be typed directly, loaded with LOAD "filename.bas", saved with SAVE "filename.bas", cleared with NEW, listed with LIST, etc. You may pass source files through the command line, drag and drop, or association.

The interpreter features a classic style line mode editor and will run on all versions of Windows 95 and up. There's just enough commands and functions to be useful. My goal is for this language to be standard and minimal. I don't want to get crazy with the syntax like with Craft Basic and Commando Basic. This will be my "normal" BASIC along side Net Basic.

So, with Net Basic being written in PHP and Express BASIC in C, I think this will be the last language I will make for a long time hopefully.

Get it here: https://lucidapogee.com/index.php?page=expressbasic

Here's a few examples...

10 REM ROCKET.BAS by Brian Tung
20 REM Modified to work with Express Basic
30 LET a = 1.032
40 LET d = 1
50 PRINT "Earth gravity in light-years per year squared: "; a
55 PRINT "Distance in light-years (0-100 million): "; d
60 IF d >= 0 AND d <= 100000000 THEN 80
70 PRINT "Distance must be between 0 and 100 million l-y"
75 END
80 LET d1 = d / 2
90 LET t = SQR(d1 * d1 + (2 * d1 / a))
100 LET x = a * t
110 LET m = 1
120 IF x >= 0 THEN 130
125 LET m = -1
130 LET s = LOG(ABS(x) + 1)
140 LET s1 = s + 1
150 LET x1 = (EXP(s) - EXP(s * -1)) / 2 - ABS(x)
160 LET s1 = x1 / (EXP(s) + EXP(s * -1)) / 2
170 LET s = s - s1
180 IF ABS(s1) > .0000001 THEN 150
190 LET t1 = 1 / a * s * m
200 LET v = a * t / SQR(1 + (a * t) * (a * t))
210 PRINT "Time on Earth: "; 2 * t; " years"
220 PRINT "Time on board: "; 2 * t1; " years"
230 SHELL "pause"

1 REM MODIFIED TO WORK WITH EXPRESS BASIC
10 PRINT "HURKLE"
20 PRINT "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY"
30 PRINT
110 LET N=5
120 LET G=10
210 PRINT
220 PRINT "A HURKLE IS HIDING ON A ";G;" BY ";G;" GRID. HOMEBASE"
230 PRINT "ON THE GRID IS POINT 0,0 IN THE SOUTHWEST CORNER,"
235 PRINT "AND ANY POINT ON THE GRID IS DESIGNATED BY A"
240 PRINT "PAIR OF WHOLE NUMBERS. THE FIRST NUMBER IS"
245 PRINT "THE HORIZONTAL POSITION AND THE SECOND NUMBER"
246 PRINT "IS THE VERTICAL POSITION. YOU MUST TRY TO"
250 PRINT "GUESS THE HURKLE'S GRIDPOINT. YOU GET ";N;" TRIES."
260 PRINT "AFTER EACH TRY, I WILL TELL YOU THE APPROXIMATE"
270 PRINT "DIRECTION TO GO TO LOOK FOR THE HURKLE."
280 PRINT
285 LET A=INT(G*RND)
286 LET B=INT(G*RND)
290 LET K = 0
310 LET K = K + 1
320 PRINT "GUESS #";K
330 INPUT "X: ", X
335 INPUT "Y: ", Y
340 IF ABS(X-A)+ABS(Y-B)=0 THEN 500
350 REM PRINT INFO
360 GOSUB 610
370 PRINT
380 IF K <= N THEN 310
410 PRINT
420 PRINT "SORRY, THAT'S ";N;" GUESSES."
430 PRINT "THE HURKLE IS AT ";A;",";B
440 PRINT
450 PRINT "LET'S PLAY AGAIN, HURKLE IS HIDING."
460 PRINT
470 GOTO 285
500 REM
510 PRINT
520 PRINT "YOU FOUND HIM IN ";K;" GUESSES!"
540 GOTO 440
610 PRINT "GO ";
620 IF Y=B THEN 670
630 IF Y<B THEN 660
640 PRINT "SOUTH";
650 GOTO 670
660 PRINT "NORTH";
670 IF X=A THEN 720
680 IF X<A THEN 710
690 PRINT "WEST";
700 GOTO 720
710 PRINT "EAST";
720 PRINT
730 RETURN
999 END

1 REM https://rosettacode.org/wiki/Attractive_numbers
10 FOR x = 1 TO 120
20 LET n = x
30 LET c = 0
40 IF n MOD 2 <> 0 THEN 70
50 LET n = INT(n / 2)
60 LET c = c + 1
70 IF n MOD 2 = 0 THEN 40
80 FOR i = 3 TO SQR(n) STEP 2
90 IF n MOD i <> 0 THEN 120
100 LET n = INT(n / i)
110 LET c = c + 1
120 IF n MOD i = 0 THEN 90
130 NEXT i
140 IF n <= 2 THEN 160
150 LET c = c + 1
160 IF NOT(PRIME(c)) THEN 180
170 PRINT x,
180 NEXT x
190 PRINT
200 SHELL "pause"

1 REM https://rosettacode.org/wiki/Golden_ratio/Convergence
5 PRECISION 6
10 LET phi0 = 1
20 LET phi1 = 1 / phi0 + 1
30 LET d = ABS(phi1 - phi0)
40 LET phi0 = phi1
50 LET i = i + 1
60 IF d >= .00001 THEN 20
70 PRINT "result: "; phi1; " after "; i; " iterations"
80 PRINT "the error is approximately "; phi1 - (.5 * (1 + SQR(5)))
90 SHELL "pause"

1 REM https://rosettacode.org/wiki/Nth_root
5 PRECISION 6
10 LET a = INT(RND * 5999) + 2
20 PRINT "nth root of "; a; "..."
30 FOR n = 1 TO 10
40 LET p = .00001
50 LET x = a
60 LET y = a / n
70 IF ABS(x - y) <= p THEN 110
80 LET x = y
90 LET y = ((n - 1) * y + a / y ^ (n - 1)) / n
100 IF ABS(x - y) > p THEN 80
110 PRINT n; " : "; y
120 NEXT n
130 SHELL "pause"

CharlieJV

Good stuff.

BTW, typo: "mantain"

QuoteThe goal of this language is to develop and mantain a syntax

Lucidapogee

"Mantain" lol this is what happens when I type stuff after midnight and don't spell check. Fixed. Thank you.

johnno56

Normally I can run Windows programs, on my Linux machine, using Wine. But it looks like EB may be designed for 32 bit. Have no fear... I have a VM.... Moo Ha Ha Ha...

Looking forward to taking EB "out for a spin". Nostalgia. Gotta love it!
May your journey be free of incident.  Live long and prosper.

johnno56

Hmmm... Interesting... Not used to keying in capitalized reserved words... But... "When in Rome"... lol

Nice version of Basic. Well done!
May your journey be free of incident.  Live long and prosper.

Lucidapogee

I'm happy to bring out some nostalgia  8)

It isn't a case sensitive language. I am writing the examples in caps to make the "true" BASIC like syntax shine.

The thought of running it on Linux is interesting to me. One of my goals with this being written in C is to port it to various platforms.

I am thinking about dos, linux, windows ce, arduino, android.

Hopefully it won't be to difficult to port. It uses a few Windows only library calls that should be easy enough to replace.

johnno56

Ok... Lowercase works just fine... saves a few key strokes... lol

The SOUND statement does not seem to work... not a concern... Wine is nowhere near 100% compatible with Window commands anyway...

I have also got EB running on Windows XP via a VM. Sound does not work either.... Oh well... Worth a shot...

Going to test EB with some simple Astronomy programs... fingers crossed... fortunately it's all text... lol

J
May your journey be free of incident.  Live long and prosper.

Lucidapogee

I'm nervous to see how well it works out for you. I made an effort to make sure all the functions and operators behave as expected, but this project is only a week old. It has had limited testing. Mostly just the included examples.

It will be exciting to see what you find. If anything is wrong, I will do my best to fix the problems.

johnno56

As I stated earlier, I am not overly concerned about the sound not working, as I am used to a LOT of things going "amiss" with compatibility issues. But, as I work my way through the examples and other minor projects, I will certainly keep you informed of any "random features" that I may encounter... In my case I will test via Wine and the VM....

J
May your journey be free of incident.  Live long and prosper.

Lucidapogee

I will be looking towards compiling this for linux. A few changes in the code will have to take place.

For SOUND, ALERT, TIMER, MILLISECS, and a few things I am using windows.h library. This should be easy to omit or replace.

In the windows.h library I am using Beep for sound. I noticed dos.h has a sound function that could be used as well. Not sure what the Linux equivalent is. Stuff like that is just a bonus anyway compared to the core BASIC functions.

I tried adding the allegro.h library, but it conflicts with windows.h. I also tried adding graphics.h and had no luck getting it to work with Dev-C++ that I am using to compile. Finally, I also had no luck with using GDI from windows.h itself. I just need more time to study windows.h. It would be nice to add screen, color, pset, etc.

I also plan to add else/endif eventually. Just don't want to add too much stuff that isn't "standard."

One thing I need to figure out is USING.

This is an intimidating project to tackle. Your feedback is helpful to me. Especially when it comes to the expression evaluation, logic, and structure.

johnno56

Hit a snag... EB no longer executes via Wine... I am actually surprised that it lasted as long as it did. Looking at the error message I would hazard a guess to say that it looks like 32bit and 64bit are not playing together well...

I will continue testing via my VM...

*sigh*



May your journey be free of incident.  Live long and prosper.

Lucidapogee

I'm using the setting to compile for 386 compatibility. Maybe that has something to do with it?

I have been researching various libraries. Hopefully I will get this running with graphics and cross platform compatibility soon-ish.

johnno56

I tried running an unrelated Win32 programme and it too failed... hmm.. Possible Wine corruption? Purged Wine from the system. Rebooted and installed a fresh version of Wine. EB (and other unrelated executable) seem to be behaving. I must remember this fix... Just in case...
May your journey be free of incident.  Live long and prosper.

Lucidapogee

#13
That's good news. Just needed the fresh install.

I have been working on trying to implement graphics and have had no luck with libraries. Ended up borrowing more BCX routines. Amazingly, you can draw to the console directly! Wow!

There's now two versions of Express Basic. Minimal and Extended Editions. The minimal contains no Windows features and should be easy enough to port to Linux while the Extended Edition depends on Windows for graphics commands.

There's now updated links on the download page for the Minimal and Extended Editions.

I'll post the downloads here as well:

Minimal Edition: https://www.lucidapogee.com/download.php?file=expressbasicminimaledition.zip
Extended Edition: https://www.lucidapogee.com/download.php?file=expressbasicextendededition.zip

New features in the extended edition include:

PSET (x, y)
LINE (x1, y1)-(x2, y2)
CIRCLE (x, y), radius
COLOR doscolors
RGB red, green, blue
WAV "sync:filename.wav"

PSET only accepts x and y parameters.
LINE only accepts x1, y1, x2, and y2.
CIRCLE only accepts x, y, and radius
COLOR accepts 0-15
RGB accepts 0-255 for rgb values.
Expressions may be used anywhere in these commands. This includes expressions with ()-(). For example, LINE ((150/2)-(3*2),(14*5)-(6+7))-((123-44)-(5-66),(42*7)-(66+45)) will draw the same line in QBasic and Express BASIC without modification. I went out of my way to require the extra weird syntax with the ()-().
PSET and CIRCLE are similar.
WAV requires sync: or async: in the quotes to the left of the filename. I thought this was a quick and dirty solution.

The Minimal Edition does not have the following commands: ALERT, LOCATE, PSET, LINE, CIRCLE, COLOR, RGB, WAV, SOUND

I changed the TIMER and MILLISECS function to use clock() instead of GetSystemTime(). This removes the windows.h dependency from both editions for randomization seeding, TIMER, and MILLISECS. For timer, I am just using clock()/1000. Millisecs is clock(). The big difference is that now the count is from when the program starts. For the random seeding, I am using time(NULL).

I also fixed a little issue with LOCATE. It was expecting 0, 0 as the top left. Now it accepts 1, 1 like QBasic.

Here's some of the graphics examples included with the Extended Edition:

1 REM https://rosettacode.org/wiki/Draw_a_sphere
5 CLS
10 LET j = 2
20 FOR i = 51 TO 0 STEP j * -1
30 FOR k = PI * -1 TO PI STEP .05
40 PSET (51 + i * sin(k), 52 + 51 * cos(k))
50 PSET (51 + 51 * sin(k), 52 + (i - 1) * cos(k))
60 NEXT k
70 LET j = j + 1
80 NEXT i
90 SHELL "pause"


1 REM https://rosettacode.org/wiki/Barnsley_fern
2 CLS
5 COLOR 10
10 FOR i = 1 TO 10000
20 LET r = RND
30 IF NOT(r > 0 AND r < .01) THEN 60
40 LET x = .0
50 LET y = .16 * y
60 IF NOT(r > .01 AND r < .08) THEN 90
70 LET x = .22 * x - .26 * y
80 LET y = -.23 * x + .22 * y + 1.6
90 IF NOT(r > .075 AND r < .15) THEN 120
100 LET x = .15 * x + .28 * y
110 LET y = -.29 * x + .24 * y + .44
120 LET x = .85 * x + .04 * y
130 LET y = -.04 * x + .85 * y + 1.6
140 LET x1 = (x + 3) * 20
150 LET y1 = 200 - y * 20
160 PSET (x1, y1)
170 NEXT i
180 SHELL "pause"


1 REM https://rosettacode.org/wiki/Mandelbrot_set
5 CLS
10 LET max = 15
20 LET w = 319
30 LET h = 199
40 LET px = 0
50 LET sy = (py - h / 2) / 150 
60 LET sx = (px - w / 2) / 150
70 LET i = 0
80 LET x = 0
90 LET y = 0
100 LET xy = x * x + y * y
110 LET xx = x * x - y * y + sx + .1
120 LET y = 2 * x * y + sy
130 LET x = xx
140 LET i = i + 1 
150 IF i < max AND xy < 1 THEN 110
160 RGB 220 + i * x, 220 + i * y, 230 + i * xy
170 PSET (px, py)
180 LET px = px + 1
190 IF px < w THEN 50
200 LET py = py + 1
210 IF py < h THEN 40
220 LOCATE 25, 1
230 SHELL "pause"


1 REM https://rosettacode.org/wiki/Munching_squares
5 CLS
10 LET s = 255
20 FOR y = 0 TO s
30 FOR x = 0 TO s
40 LET r = x XOR y
50 RGB r, r * 2, r * 3
60 PSET (x, y)
70 NEXT x
80 NEXT y
90 LOCATE 25, 1
100 SHELL "pause"


2 CLS
5 COLOR 15
10 FOR f = 0 TO 1000 STEP .1
20 LET x = x + SIN(f * f)
30 LET y = y + COS(f * f)
40 PSET (x + 200, y + 20)
50 NEXT f
60 SHELL "pause"


There's probably more I am forgetting to mention and even more to do. As always.  8)

Lucidapogee

There was a problem with CLS where it was clearing the console text, but not the graphics. I applied a simple "hack" to remedy that for now. This only applies to the extended edition where graphics are used.

The IF statement was missing the ability to use an expression (as opposed to a literal value) as the line number, so I fixed that to be consistent with GOTO and GOSUB.

I added the CHR$() function. This is the only string function and for now, it's solely intended to be used with PRINT. This way you may display double quotes and other special characters.

For example PRINT CHR$(34); "Hello, world!"; CHR$(34)