remy / txt2bas

ZX Spectrum BASIC conversion tooling (specific support for NextBASIC)
19 stars 0 forks source link

Create a new directive #define #19

Closed paulossilva closed 4 years ago

paulossilva commented 4 years ago

In some IDE editors we have an option to define some constants for convenience, like number and string constants, that are used throughout the code. It is very helpful and adds to code readability and maintainability.

Creating a #define directive for your VSCode NextBasic plugin would be a very nice addition, one that may be hard for the .txt2bas native command to implement.

Here an example syntax and use of this directive: . . .

define PLAYER_SPRITE 1

define ENEMY_SPRITE 10

define READY$ "Player Ready"

. . . PROC checkCollision() let %c = SPRITE OVER (PLAYER_SPRITE, ENEMY_SPRITE, 0, 0) . . . PROC StartPlay() PRINT AT 10,12; READY$

paulossilva commented 4 years ago

Consider that your plugin export routine would need to replace all references for #define clauses before generating the .bas file.

The name used in the define clause could be any given string sequence. The use of a trailing $ for strings is just a useful convention.

remy commented 4 years ago

Just wanted to say, that I like this idea and it's been something I was thinking about before. I think it's that I'm a little nervous of diverging from following the native .txt2bas - but doesn't mean this doesn't have legs…

remy commented 4 years ago

I've been thinking about this some more, and from a technical perspective there's not a great deal required to actually implement this as a feature. It would be limited to constants and the #define would have to appear before it's first used, but since my lexer would see PLAYER_SPRITE as an identifier, my code would look it up against the define table and replace it in the (quasi) AST for a number or string.

What's even more interesting (and particularly for my own needs) are macros, even at a simple level. I've found I need to inline a lot of code, creating repeating code (for better performance) and a macro would make the source much more manageable (but it's a lot trickier to implement).

paulossilva commented 4 years ago

Good point! I haven't thought of macros before but it would make another great addition, indeed. In C preprocessor, actually #define can be used to define constant and code macros (https://gcc.gnu.org/onlinedocs/cpp/Macros.html). The big difference I think of, is that in NextBasic we wouldn't use macros to call functions. Instead, code macros would be more like the ones used in assemblers, i.e., for referencing frequently used code snippets (http://faculty.cs.niu.edu/~byrnes/csci360/notes/360macro.htm).

Mind that macros may be used with parameters, which are very useful for defining function-like macros (https://gcc.gnu.org/onlinedocs/cpp/Macro-Arguments.html#Macro-Arguments).

For instance, we could create macros like this:

$define inc(x) x=x+1

And use it as this:

inc(%a)

or

inc(counter)

which would translate to %a=%a+1 and counter=counter+1, respectively. Remind that LET is now optional in NextBasic.

Ideally, I would think of more sophisticated ways of using macros, like:

#define x++ x=x+1

However, that would require a way of mixing parameters with the macro's name, perhaps by defining a character for indicating a single-letter parameter, like #define &x++ &x=&x+1 or even #define &x++&y &x=&x+&y.

Regarding implementing macros in your plugin, I think that getting basic macro functionality, even with parameters, wouldn't be such a big stretch from implementing constant macros. The only thing that comes to mind now is a way of delimiting the macro's body, for multiple-line code macros. Something like #enddef or #endmacro.

remy commented 4 years ago

So, a simple version of this is now live - and inherited in the vscode extension as well as all places that use txt2bas.

It's limited to simple text: #define SPEED=100 on a line of it's own, and then in the code something like %x = %x + #SPEED.

The value on the define is fully tokenised, so it could be an inline expression, but you'll need to be wary of usage with integers in nextbasic - only to make sure you don't end up with the % more than once.

The #define x=y statements can be anywhere in the code (though I personally prefer up front) - but this change does mean that the source code cannot be transformed using the native .txt2bas when using the #define statement.

I'm going to close this now as much as I like/want to create #macro there's not a full AST parser in place to be able to correctly transform the code (your examples are exactly the kind of useful thing though), but #define personally gets me a long way towards simpler code - since I'm no longer limited to 26 integer variables.