Is it still alive?

A forum for users of EhBASIC (Enhanced BASIC), a portable BASIC interpreter for 6502 microcomputers written by Lee Davison.
Post Reply
DaveK
Posts: 34
Joined: 30 Aug 2008
Location: Kent, UK

Is it still alive?

Post by DaveK »

The last version of 6502 EhBASIC on Lee's website is 2.09, dated 2005. Is the project still under development? Any plans? Has the website moved?
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

I think that it's simply "mature technology."
leeeeee
In Memoriam
Posts: 347
Joined: 30 Aug 2002
Location: UK
Contact:

Post by leeeeee »

DaveK wrote:
The last version of 6502 EhBASIC on Lee's website is 2.09, dated 2005. Is the project still under development? Any plans? Has the website moved?
No, nothing's moved. That is the current version.
kc5tja wrote:
I think that it's simply "mature technology."
That's pretty much the case. I only started EhBASIC because I wanted some high level language that I could easily port to any target hardware and be able to use it interactively, so I wouldn't be left wondering if it was my new hardware or my new assembly language code that was broken.

EhBASIC as it is has gone quite a way beyond that goal. Features I'd always wanted from a BASIC such as the ability to easily use hex and binary in the code and for input and output were added. Commands were added that made coding for hardware easier as were commands that made writing code itself easier.

Version 2.xx came with the lessons learned in coding a Motorola 68K version from scratch and, while it looks outwardly very similar to 1.xx versions, internally it changed quite a bit and became a fair bit quicker. 2.09 is the last completed version and while it can probably be improved it works better than I ever expected when I started sometime in the last millenium.

I do plan a similar but expanded version for the 65816 but not having an assembler/simulator like Michal Kowalski's simulator for the 6502 and having all of my 65816 hardware in storage, along with a lot of other things, until I finally sell this place and move has precluded any real progress on that to date.

If there's any undocumented feature that needs addressing I'm always up for that, EhBASIC isn't abandoned, it's just .. resting.

Lee.
DaveK
Posts: 34
Joined: 30 Aug 2008
Location: Kent, UK

Post by DaveK »

How would I go about adding keywords? I've implemented some stuff for a graphical LCD and would like to go from CALL PLOT,x,y to PLOT x,y.

Longer variable names would be nice but probably difficult to change.
leeeeee
In Memoriam
Posts: 347
Joined: 30 Aug 2002
Location: UK
Contact:

Post by leeeeee »

How to add a new command to EhBASIC.

As this is a primary command, it can start a statement, first insert a new entry into the list of primary command tokens. It doesn't particularly matter where in the list.

E.g.

Code: Select all

TK_DOKE           = TK_POKE+1       ; DOKE token
TK_CALL           = TK_DOKE+1       ; CALL token
TK_DO             = TK_CALL+1       ; DO token
TK_LOOP           = TK_DO+1         ; LOOP token
.. becomes ..

Code: Select all

TK_DOKE           = TK_POKE+1       ; DOKE token
TK_CALL           = TK_DOKE+1       ; CALL token
TK_PLOT           = TK_CALL+1       ; PLOT token      new command entry
TK_DO             = TK_PLOT+1       ; DO token        modified entry
TK_LOOP           = TK_DO+1         ; LOOP token
Next put a corresponding new entry in the command vector table that starts at LAB_CTBL. This must be in the same relative location as the token value.

E.g.

Code: Select all

      .word LAB_POKE-1        ; POKE
      .word LAB_DOKE-1        ; DOKE
      .word LAB_CALL-1        ; CALL
      .word LAB_DO-1          ; DO
.. becomes ..

Code: Select all

      .word LAB_POKE-1        ; POKE
      .word LAB_DOKE-1        ; DOKE
      .word LAB_PLOT-1        ; PLOT      new command
      .word LAB_CALL-1        ; CALL
      .word LAB_DO-1          ; DO
Now add an entry in the keyword tables.

E.g.

Code: Select all

LBB_PI
      .byte "I",TK_PI          ; PI
LBB_POKE
      .byte "OKE",TK_POKE      ; POKE
.. becomes ..

Code: Select all

LBB_PI
      .byte "I",TK_PI          ; PI
LBB_PLOT
      .byte "LOT",TK_PLOT      ; PLOT     new command keyword
LBB_POKE
      .byte "OKE",TK_POKE      ; POKE
In this case there are already keywords that start with "P" so it's just a case of adding this one entry but if you were adding a keyword that starts with a so far unused letter then you also need to add entries in the first character table at TAB_1STC and in the character pointers table at TAB_CHRT and make a new character table for your entry.

Next you need to add an entry in the LIST decode table, this again must be in the same relative location as the token value.

E.g.

Code: Select all

      .byte 4,'P'
      .word LBB_POKE          ; POKE
      .byte 4,'D'
      .word LBB_DOKE          ; DOKE
      .byte 4,'C'
      .word LBB_CALL          ; CALL
      .byte 2,'D'
      .word LBB_DO            ; DO
.. becomes ..

Code: Select all

      .byte 4,'P'
      .word LBB_POKE          ; POKE
      .byte 4,'D'
      .word LBB_DOKE          ; DOKE
      .byte 4,'P'             ;           new keyword length and first character
      .word LBB_PLOT          ; PLOT      new keyword pointer
      .byte 4,'C'
      .word LBB_CALL          ; CALL
      .byte 2,'D'
      .word LBB_DO            ; DO
The last thing to add is the code for the new command which should be the same as the code you used for the CALL version but without the first scan for the comma. So instead of say using LAB_SCGB, scan for "," and get byte, you could use LAB_GTBY, get byte parameter, to get the X value.

.. and that should do it.
Quote:
Longer variable names would be nice but probably difficult to change.
Not that difficult but wastefull of space and speed, unless you want variable length names and then it does get more awkward. The first two significant characters give you over 3000 different variables of each type and you can append any number of other characters of your choice as long as you avoid keywords.

Lee.
DaveK
Posts: 34
Joined: 30 Aug 2008
Location: Kent, UK

Post by DaveK »

Thanks for your help. I will try this today.
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

The earliest Forth systems represented word names using the first three characters plus a length byte. This allowed a single 32-bit compare instruction to isolate the overwhelming majority of words when performing a dictionary lookup.

Maybe the same technique would apply for BASIC variable names as well. For example, you could have two variables PLOT (pointer to the graphics plot routine) and PLOTLINE (pointer to some line drawing code). Both variables would start with the PLO prefix, but they'd be further disambiguated by the length byte (4 in the former case, 8 in the latter).

A collision occurs only when you share both a common prefix and length. Hence, A=PLOXXXXX and A=PLOTLINE both assign the same value to A.

Yes, this is a very crude form of hashing the variable name. :)

Just an idea though.
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

leeeeee wrote:
The first two significant characters give you over 3000 different variables of each type and you can append any number of other characters of your choice as long as you avoid keywords.

Lee.
Actually, precisely because EhBASIC lacks any kind of abstraction mechanisms whatsoever, and all variables are global, the names you assign to a variable become increasingly important as their quantity increases. Two-character variable names suffice for simple routines only.

Thankfully, if you're crafty with arrays, you can make yourself a stack, and implement your own support for abstraction. It's wordy to do, but it works -- I had to do it for many a VisualBasic application before VB learned proper abstraction constructs.

The technique applies to multiple data types too:

Code: Select all

10 DIM S$(10),I(10)
20 SP=10:IP=10
30 SP=SP-1:S$(SP)="HELLO WORLD"
40 GOSUB 100:REM SP=10, I=9 AT THIS POINT
50 PRINT "THE LENGTH OF THE STRING IS:";I(IP)
60 IP=IP+1:END
100 IP=IP-1:I(IP)=LEN(S$(SP)):SP=SP+1:RETURN
Example,

Code: Select all

10 DIM I(30):REM a simple stack of integers (effectively infinite depth)
11 IP=29:REM Integer stack pointer
...
999 REM A trivial addition example
1000 I(IP+1)=I(IP+1)+I(IP):IP=IP+1:RETURN
1999 REM ( a b c -- z -z ) compute the quadratic formula
2000 T = (-(I(IP+1)) + sqrt((I(IP+1))**2 - 4*(I(IP+2))*(I(IP)))) / 2*(I(IP+2))
2010 I(IP+2)=T:I(IP+1)=-T:IP=IP+1:RETURN
The code is ugly and wordy, like I said. However, it also allows for proper recursion, if your stack is deep enough. Here's how you might call the quadratic routine, for example:

Code: Select all

100 IP=IP-3
110 I(IP+2)=(a)
120 I(IP+1)=(b)
130 I(IP)=(c)
140 GOSUB 2000
150 REM I(IP) contains -z, I(IP+1) contains +z
Remember to update IP as you produce or consume values off the stack!
kc5tja
Posts: 1706
Joined: 04 Jan 2003

Post by kc5tja »

I also wanted to add:

The technique can be applied to multiple data types as well.

Code: Select all

10 DIM S$(100),I(100):REM THE STACKS
20 SP=100:IP=100:REM THE STACK POINTERS

30 REM FIND THE LENGTH OF A STRING.
40 SP=SP-1:S$(SP)="HELLO WORLD!"
50 GOSUB 1000
60 PRINT "THE LENGTH OF THE STRING IS: ";I(IP)
70 IP=IP+1
80 END

1000 REM JUST TO PROVE IT CAN BE DONE, WE FIND
1001 REM THE LENGTH OF THE STRING THE HARD WAY:
1002 REM RECURSIVELY!
1003 REM THIS IMPLEMENTS THE FOLLOWING EQUATIONS:
1004 REM LEN "" = 0
1005 REM LEN S = 1+(LEN (TAIL S))
1010 IF S$(SP)="" THEN IP=IP-1:I(IP)=0:SP=SP+1:RETURN
1020 SP=SP-1:S$(SP)=MID$(S$(SP+1),1):GOSUB 1000
1030 I(IP)=I(IP)+1:RETURN
Obviously, you'll want to use LEN() to compute the length of a string. I'm merely illustrating that using stacks like this in BASIC prove powerful enough to compute arbitrary lambda expressions.

Remember, the original version of Smalltalk was written in BASIC!
Post Reply