I recently wrote a TinyBasic for the 6502[*] and I included hex constant entry using the Acorn “standard” of prefixing with an ampersand:
> A = &CAFE
Printing again uses the Acorn standard with a twiddle:
> PRINT ~A CAFE
Whatever prefix you pick will never please everyone - 0h is a typical Intel style prefix, $ may be more MOS/Motorola style. 0x more for C programmers and so on… And a leading zero without a modifier? Well, that’s Octal, isn’t it?
Tiny Basic uses $ for string variables (as a prefix) so overloading it would be problematic and using 2 characters is just a waste of time (as in execution time - TinyBasic is slow enough already!)
My other BASIC (RTB - written in C, runs under Linux and standalone on a Pi) uses the “C” stadard of 0x for hex and 0b for binary.
Indeed, BBC Basic uses & as a hex prefix. There’s some subtle special handling to allow it to be unsigned, even though integers are signed. A%=&FFFFFFFE
for example is legal, and A% has the expected value, which Basic will normally treat as -2.
Note that ~ for hex output can also be used in other contexts, such as STR$~var
Acorn’s Atom Basic used # for hex constants, I believe.
I do think supporting hex in and out is a very good idea, both for practical and for teaching (or learning.) I think the exact syntax is not too important.
The usual method for converting from hex was to use something like VAL("&"+h$).
(TIL that Locomotive BASIC 1.1 had DEC$(numeric expression, format template) — a little like sprintf() except using IBM’s PRINT USING syntax. DEC$(PI*10^7,"££########,.##")would return the string “£31,415,926.50”. My Amstrad CPC464 only had BASIC 1.0, so I never knew about this.)
Atom BASIC also uses a somewhat interesting approach to strings, rather using a string operator “$” than a dedicated name space. It’s actually closer to C than to other BASICs.
10 DIM A(11)
20 $A = "HELLO WORLD"
Here, DIM A(11) reserves memory and $A points to the start address of this. (Meaning, it’s really an indirection.)
However, in PRINT statements, if the $ operator is followed by a value less than 256, this is interpreted as a literal character value.
E.g., here used for encoding cursor movements (also demonstrating # for hex values):
1 REM Random Walk
20 PRINT $ABS(RND)%4+8, $(#A0+ABS(RND)%#40), $8
30 UNTIL 0
This may be an interesting idea for any BASIC.
(However, this also means that the entire expression has to be evaluated first, in order to determine, whether this is a literal character value or a start address in memory, from which to print a string. It also means that with regular strings, in an expression like “$A”, “A” returns the base address of the respective array in memory. I guess, this also suggests a C-like termination, but I don’t know the details.)
I’ve read that Atom BASIC was inspired by a TinyBasic variant called NIBL - which was used on the SC/MP or INS8060 systems in the mid-late 70s… It has a similar approach although no DIM statement as such, but you did have a keyword that told you where the start of free RAM was:
A = TOP
$A = "Hello, world!"
And if you wanted another string - well, allocation is left as an exercise to the user, ie.
B = A + 20 : REM $A can be 19 characters long
$B = "Hi there"
There wasn’t a way to print characters in NIBL though - well, not easily. You can pluck a character out of a string, insert it into another string, add on a CR and print that string… (The CR was the string terminator in NIBL and wouldn’t be printed).
Apparently, Atom BASIC allows for pointer arithmetic and accessing random slices in a string.
The following program suggests termination by ASCII 13 (value of the empty string “”, in the following example “;” is the statement separator):
For example:, if the following is executed:
10 DIM A(10)
30 $A+5=""; $A=$A+1
then string A will have the value “TOMB”.
I’ve no idea, if this is any different from NIBL.
Just for completeness sake, the “?” operator allows us to read a spcific character inside a string, as in “A?3”. (“LEN()” and string comparison work as usual.)
On a more abstract level, this should allow us to pack arbitrary structures into a string and to access random slices of memory (both read and write). Which is actually quite powerful.
I think that will work in NIBL - I don’t have a working system to test it on, however my own TinyBasic, GIBL was written after many hours pouring over the NIBL sources and is in-parts, a direct translation to 6502 code (and in many other parts a complete re-write) and yes, ? is byte-indirection. (I added ! for word indirection too) I’ll try it later tonight.
I fear it is too late for that. … but do feel free to re-write every unix/unix-like utility, re-write the man pages, the system libraries and re-educate everyone who came from the PDP-8 era into the PDP-11 era …
I teach a second-year University programming course that uses C. Almost every semester I run into at least one student who gets into trouble because they have a leading zero on a decimal number. (Admittedly this is out of hundreds of students, but for every one I see there is almost assuredly a handful who figured it out without me.)
I do find this to be a regrettable choice. It was, however, an improvement on most of the DEC tools for the PDP-11, which simply assume that numbers are octal unless you follow them by a bare . (period).
(Forgoing octal notation completely, isn’t a great option, either. There were a few years, when the leading zero notation was illegal in JS in strict mode, but the 0o… notation wasn’t yet in the standard or, as it finally was, not implemented. Which was actually quite an issue, if you were dealing with vintage software and emulation.)
TRS-80 Model 1 Disk BASIC adds hexadecimal constants with a &H prefix and octal ones with &O both representing signed 16-bit integers - so &HFFFF = -1. For octal constants, the O can be omitted so &77777 = 32767.
Oddly, these constants can’t be used in DATA statements.