As discussed in a previous posting, I’ve been musing over the development of a modernised version of the classic procedural BASIC language, especially with the Raspberry Pi in mind.
With this in mind I’ve been setting out some goals for a project and working a little on some of the syntactical details to bring structures, advanced for-loop constructs and other modern features to a BASIC language as backwardly compatible with the old Sinclair QL SuperBASIC as possible.
So, here are the goals:
- The language is aimed at both the 13 year old bedroom coder, getting him/her enthused about programming, and the basic needs of general scientist. (Surprisingly, the needs of these two disparate groups are very similar.)
- It must be platform agnostic and portable. It must also have a non-restrictive, encumbered license, such as the GPL, so probably Apache, so as to allow it to be implemented on all platforms, including Apple’s iOS.
- It must have at least two, probably three, levels of language, beginner, standard and advanced. The beginner would, like its predecessors in the 8bit era, be forced to use line numbers, for example.
- It must have fully integrated sound and screen control available simply, just as in the old 8bit micro days. This, with the proper manual, allow a 13 year old to annoy the family within 15 minutes of the person starting to play.
- The graphical capability must include simple ways to generate publishable scientific graphical output both to the screen and as encapsulated Postscript, PDF and JPEG.
- The language must have modern compound variables, such as structures, possibly even pseudo-pointers so as to be able to store references to data or procedures and pass them around.
- The language should be as backwardly compatible with Sinclair QL SuperBASIC as possible. It’s a well tested language and it works.
- The language should be designed to be extendable but it is not envisaged that this would be in the first version.
- The language IS NOT designed to be a general purpose application development language, though later extensions may give this ability.
- The language will have proper scoping of variables with variables within procedures being local to the current call, unless otherwise specified. This allows for recursion.
- All devices and files are accessed via a URI in an open statement.
- Channels (file descriptors) must be a special variable type which can be stored in arrays and passed around.
As I said earlier, I’ve been thinking about how to do a great deal of this syntactically as well. This is where I’ve got so far:
[Edit: The latest version of the following information can be found on my website. The information below was correct at 10am 23rd February 2012.]
Variables.
Variable names MUST start with a alphabetic character and can only contain alphabetic, numeric and underscore characters. A suffix can be appended so as to give the variable a specific type, e.g. string. Without a suffix character the variable defaults to a floating point value.
Suffixes are:
$ string
@ pointer
Compound variables.
Compound variables (structures) can be created using the “DEFine STRUCTure” command to create a template and then creating special variables with the “STRUCTure” command:
DEFine STRUCTure name
varnam
[…]
END STRUCTure
STRUCTure name varnam[,varnam]
An array of structures can also be created using the STRUCTure command, e.g.
STRUCTure name varnam(3)
The values can be accessed using a “dot” notation, e.g.
DEFine STRUCTure person
name$
age
DIMention vitals(3)
END STRUCTure
STRUCTure person myself, friends(3)
myself.name$ = “Stephen”
myself.age = 30
myself.vitals(1) = 36
myself.vitals(2) = 26
myself.vitals(3) = 36
friends(1).name$ = “Julie”
friends(1).age = 21
friends(1).vitals(1) = 36
friends(1).vitals(2) = 26
friends(1).vitals(3) = 36
As with standard arrays, arrays of structures can be multi-dimentional.
Structures can contain any number of standard variables, static arrays types and other structures. However, only structures defined BEFORE the one being defined can be used. Structure definitions are parsed before execution of the program begins. Structure variable creation takes place during execution.
Loops.
FOR/NEXT:
FOR assignment (TO expression [STEP expression] | UNTIL expression | WHILE
expression) [NEXT assignment]
..
[CONTINUE]
..
NEXT [var]
The assignment flags the variable as the loop index variable. Loop index variables are normal variables.
The assignment and the evaluation of the assignment expression happen only once, when entering the loop. The test expressions get evaluated once every trip through the loop at the beginning. If the TO or UNTIL expressions evaluate to zero at the time of loop entry the commands within the loop do not get run.
The STEP operator can only be used if the loop index variable is either a floating point variable or an integer. The expression is evaluated to a floating point value and then added to the loop index variable. If the loop index variable is an integer then the value returned by the expression stripped of its factional part (as with ABS()) before being added to the variable.
WHILE/END WHILE:
WHILE expression [NEXT assignment]
…
[CONTINUE]
…
END WHILE
Equivalent to a FOR loop without an assignment using the WHILE variant e.g.
x = 10
WHILE x > 3 NEXT x += y / 3
…
END WHILE
is equivalent to
FOR x = 10 WHILE x > 3 NEXT x += y / 3
…
NEXT
DO/UNTIL:
DO
…
[CONTINUE]
…
UNTIL expression
The commands within the loop are run until the expression evaluates to a non-zero value.
Functions and procedures.
A function is merely a special form of a procedure which MUST return a numeric value. The suffix of a procedure determines its type, in the same way as variable names.
DEFine PROCedure name[(parameter[,parameter[…]])]
…
[RETURN expression]
END PROCedure
DEFine FUNction name[(parameter[,parameter[…]])]
…
RETURN expression
END FUNction
Parameters are local names with reference the passed values by reference. This means that any modification of the parameters within the procedure will change the value of any variables passed to it.
Variables created within the procedure will be local to the current incarnation, allowing recursion. Variables with global scope are available within procedures but will be superseded by any local variables with the same name.