yes, didn't think about recursion. (Which opens up the query what exactly you want to achieve and what limits you set with regards to what types of S*BASIC programs you can translate - I guess, "all", which might be a bit of a daunting task.)
ALlocating locals on the heap might open up a can of worms you'd better leave closed (Also, to me that looks a bit like interpreting the S*BASIC program at runtime in C). I'd rather go and add the LOCals you have in a called procedure as additional (by reference) parameters to the functions called from the proc like
Code: Select all
PROCEDURE HasLocals
LOCAL a, b%, c$(100)
a = DoStuff (c$);
END DEF
FUNCTION DoStuff (x$)
REMark uses a, b% and x$
RETurn something
ENDDEF
Code: Select all
void HasLocals () {
double a;
int b;
char c [100];
a = DoStuff (c, &b, &a);
}
double doStuff (/* "proper" parameter */ char *c, /* "shadow" parameters */ int *b, double *a) {
/* uses a, b, c */
return something;
}
What you cannot achieve with this method is properly translate functions that are both called from functions that have locals and from others that don't (or have another set of locals). I see no way of doing that without providing different implementations for the same function according from where it is called:
Imagine you have a "HasLocals" that calls "DoStuff" with local variables and a "HasNoLocals" that uses global variables, you'd need to have two "DoStuff" implementations:
Code: Select all
PROCEDURE HasNoLocals
REMark uses global variables!
a = DoStuff (c$)
ENDDEF
Code: Select all
double a;
int b;
char c [100];
void HasNoLocals () {
a = doStuff_cf_HasNoLocals (c);
}
void HasLocals () {
double a;
int b;
char c [100];
a = DoStuff_cf_HasLocals (c, &b, &a);
}
/* (cf means "called from") */
double doStuff_cf_HasLocals (/* "proper" parameter */ char *c, /* "shadow" parameters */ int *b, double *a) {
/* uses a, b, c locals from HasLocals */
return something;
}
double doStuff_cf_HasNoLocals (char *c) {
/* uses a, b, c global variables */
return something;
The above assumes a dumb, straight-forward translation from S*BASIC to C - With some more syntactical analysis of the original program (like analysing what a procedure modifies, and what locals (own or inherited) are actually used or not), I guess you can shorten the parameter lists and reduce the amount of _cf_ implementations quite a lot. The rule would somehow be:
"If a FN or PROC ever tries to access (or modify) a LOCal of another proc, this must be added to its parameter list as a value of or a pointer to (in case of modify) that local. A function that does that and that accesses or modifies globals in different call chains should be called with the value or pointer to the global it touches"
Tobias