Hi Roland,
Thanks again for taking interest in my code.
0. First of all, please tell me exactly which build of Oxygen you are using for compilation so that we could have identical tool chains for our experimentation.
1. My initial code used the following convention to distinguish between the remarks (both FBSL and O2 support C-style remarks in BASIC code):
-- ANSI C remarks /*...*/ = original C code author's remarks (I am not the original author of that public domain code)
-- CPP-style remarks // = my own remarks to describe the fixes I applied while translating the code to O2
-- (occasional and incomplete) BASIC-style remarks ' = Charles' later fixes to the code introduced to maintain compatibility with later O2 builds.
What kind of remarks are we going to introduce to preserve the original convention? (I presume 'rs refers to you as 'ml can refer to me?)
2. No, AFAIK goto, either local or global, cannot substitute setjmp/longjmp. The difference is that goto jumps to its jump target with the processor registers preserved as-is at the moment the jump is taken. Conversely, setjmp preserves the contents of all processor registers in that mysterious jmp_buf[_JBLEN] structure (or array of structures if nested store/restore points are allowed) in response to the setjmp call, and then uses those values to restore automatically the processor registers in case a crash occurs somewhere in between the setjmp/longjmp calls. (each (possibly nested) setjmp should be complemented with a matching longjmp for the technique to work properly)
Setjmp/longjmp is a Linuxoid (partial) equivalent to Microsoft's full-fledged SEH (structured exception handling) mechanism -- try/except pair. The difference between the two is that, while try/except keeps track of all intermediate calls (hence, both stack and malloc memory allocations) and unwinds (i.e. brings the registers and frees malloc allocations to their initial states) all of them one by one in a nested LIFO manner, setjmp/longjmp doesn't track the intermediate call stack and thus is able to bring the processor directly to its initial state only. Which means that while the stack pointer (ESP register) can be restored faultlessly effectively nullifying all of intermediate stack allocations, possible malloc memory volumes will remain un-deallocated thus causing cumulative memory leaks.
3. There is no matching free_cellseg() to alloc_cellseg() because this particular Scheme implementation does not deallocate the total number of memory segments it accumulates while executing a particular Scheme script within a common Scheme session (i.e. before you exit the Scheme prompt altogether). It rather reuses the existing (i.e. already accumulated) amount of memory segments as needed to host the number of temp vars the script actually needs, free_cell being the "head" marker of unused cells in the thus accumulated total segment memory space.
I should also note that neither the original C code nor my DynC version holds a single call to free() while there is one in the OxyScheme implementation -- see Case OP_STRAPP in the opexe_7() function. I presume it appeared there as one of Charles' (uncommented) later upgrades to my code, probably for compatibility reasons.
4. The existing OxyScheme implementation doesn't end the current Scheme session on (quit) command but rather hangs it. It is arguably a by-product of Charles' compatibility mods in Eval_Cycle().
5. Be specifically cautious with cases that involve 64-bit integers. Note well that Oxygen's quads are in fact floating-point entities stored and processed on the FPU while Scheme's (and C language's) long integers are genuine whole integers stored and returned in the eax:edx (low 32 bits:high 32 bits) register pair.
6. I am methodologically against remming out all C functions blindly. We should rather rem them out one by one running unit tests each time to see if their O2 functional equivalents reproduce the desired compatible effect in full. Do you know Scheme enough to generate at least the simplest Scheme scripts for unit testing?