The Problem(s)
There's no source code (available) for CPort, so if we need to make changes, we have to look into the grammar file, or the libCPORT library, etc. Not ideal. Well, not for me that is.
So, given this, plus the seemingly large number of foibles that CPort has, I thought that I might as well attempt to write a new version, with some changes that I want to see, and maybe, improve (!) things.
The plan is to continue to use libCPORT, after all, why bother reinventing the wheel? It may need some additional code added, but time will tell. There may be toolkits out there that are very popular - DJToolkit anyone? - and which might be useful if included in the library, or even, a separate toolkit based library. (LibTurboTK, libDJTK?)
I've been thinking about any CPort problems that I'm aware of - but it's been a long while since I used CPort, so I'm probably a bit rusty.
Did I mention I'm planning to write it all in assembler? No? That's because I'm not!
SuperBASIC Source Files
I intend for the source code to be a _SAV file, created by QSAVE (or SMSQ). Hopefully, BBQL users will still be able to compile/convert a file. We shall see.
I never liked the SuperCharge, Turbo, CPort manner of compiling the resident SuperBASIC program. So, a _SAV file it will be. It's the same thing after all, and should work in an identical manner, but those of us on BBQL with limited RAM might find that a quick QSAVE: NEW: EX C68Port ... a valid working solution. Maybe! Probably followed by a QLOAD: ED: etc!
Ok, here are my initial list of foibles and potential solutions.
FOR loops
When a FOR loop in SuperBASIC ends, the loop variable, always floating point, unless Minerva is used, holds the final value in the list of values. In C, the value is one (step) more than the final value.
I propose "fixing" this by the simply addition of an extra line of code, from this:
Code: Select all
IMPLICIT% x
...
FOR x = 1 to 10 step whatever
...
END FOR x
Code: Select all
short x; // This might be a candidate for globals.h of course!
...
for (x = 1; x <= 10; x++) {
...
}
x = 10;
See also Ranges below for other problems.
Variables - Global
In SuperBASIC, any variable declared in the main part of the program, or in any called PROCedure or FuNction, becomes globally visible. In C this is totally different where any variable declared within a function is restricted in scope to that particular function and unless passed as a parameter, to no other called functions.
To this end, to replicate the behaviour of SuperBASIC, my thoughts are to scan the program (pass 1) and write out a globals.h file containing every variable declared in the entire program, that is not declared LOCal. This globals.h file will be #included by the converted C code.
Variables - Local
In SuperBASIC, any variable declared in any called PROCedure or FuNction, as a LOCal variable, is 'globally' visible to all called PROCedures or FuNctions until the defining PROCedure or FuNction ends. In C this is totally different where any variable declared within a function is restricted in scope to that particular function and unless passed as a parameter, to no other called functions. Houston, we have a problem!
At the moment, I'm thinking of setting up some support code to enable this to be the same in any compiled/converted programs, as follows, and it gets messy here! (Final details are yet to be thought out - so thoughts may change)
I think we need a setLOcal() and a getLocal() function to set or get the value of a local parameter, or the C68 version of one anyway. Due to this being C and not C++, overloading would require different names, so:
Code: Select all
float getLocal(char *VariableName);
short getLocal_i(char *VariableName);
char *getLocal_s(char *VariableName);
short setLocal(char *VariableName, float newValue);
short setLocal_i(char *VariableName, short newValue);
short *setLocal_s(char *VariableName, char *newValue);
The LOCal variables "stack" will be an array (how big?) of pointers to a linked list of variables, possibly of the following node type, which has no idea of what to do with arrays, for now:
Code: Select all
typedef struct SB_LOCAL {
short type;
char[howBig?] varName; // Maybe a char* or whatever.
union {
short value_i;
float value;
char *value_s;
}
} SB_LOCAL;
I'm not showing next/prev pointers etc here.
The thought is to build a linked list of the above nodes, one for each LOCal variable in a PROCedure or FuNction, then push() the root pointer to the list, onto the stack of list pointers mentioned above. As we exit from a PROCedure or FuNction, pop() the pointer off and delete the list entries and the list.
When we need a LOCal, use getLocal() to fetch the value.
When we need to change a LOCal, use setLocal() to fetch the value.
We would scan the entire stack of locals, in their linked lists, from TOS to BOS until we come across the first one that matches the supplied name, and use that. Maybe, just keep a pointer to it handy somewhere, it depends, in case we need to read it or write it again?
Sounds complicated, I admit, but it's the only way I can think of to replicate the SuperBASIC behaviour in a C program. I'm trying here to get a working program "first time" without needing any manipulations to get the generated C code working/compiling - that way, frustration leads. Why? Years ago, I wrote a program in SuperBASIC and it worked well, but I wanted it in C. I used CPort on it and it converted happily, but it took me as long to tidy it all up so that it would compile and execute than if I had simply written it again from scratch in C.
Ranges
FOR loops, SELECT ON clauses and similar, take ranges of values. For example:
Code: Select all
FOR x = 1 to 5, 7 to 9 step 0.01, 123.5, 616 to 666 step 0.5
...
END FOR x
Create a temporary function with the code in it that corresponds to the body of the above loop, perhaps in a separate file, then in the main body of the program where the above loop is executed, call the function with each value in turn:
Code: Select all
for (short x = 1; x <= 5; x++) {tempForXFunction(x);}
for (float x = 7.0; x <= 9.0; x += 0.01) {tempForXFunction(x);}
tempForXFunction(123.5);
for (float x = 616; x <= 666; x += 0.5) {tempForXFunction(x);}
float x = 666.0; // Another candidate for globals.h perhaps?
Hmm, perhaps NEXT X would simply be a return, which would kick off the next iteration.
LibCPORT
Dave Walker's version of libCPORT is different from the one on Dilwyn's 'Sinclair QL Homepage' web site - I'm assuming Dave's is the de-facto one, but, is there another version out there in userland that I'm not aware of yet? (I'm not at my QL because I'm working, so I can't check versions yet!)
Right then, anyone interested? Any further comments? Is it worth pursuing? I'm intending for this to be free by the way. And open source. And on Github, so anyone can join in with the hard work!
Minerva Integer Tokenisation
Apparently, this has to always be turned off when using CPort. Does anyone know why? What effect did it have? If I remember correctly, and I don't have Minerva to check, it does something similar to IMPLICIT% for REPEat, FOR loops etc?
Cheers,
Norm.