Oxygen Basic

Programming => Example Code => General => Topic started by: Arnold on November 02, 2019, 06:04:43 AM

Title: Updating OxyScheme
Post by: Arnold on November 02, 2019, 06:04:43 AM
Hi Mike,

Quote
If you choose to engage yourself in OxyScheme upgrade, I'll be glad to give you a helping hand wherever I can.

although Christmas is coming up (sigh), I simply could not resist and started to remove the prototypes of mscvrt.dll. This was the easy part. I noticed that _strlwr does not work correctly unprototyped and I used lcase instead. I also used copy0 instead of strcpy. Maybe some more functions can be substituted.

At the moment my intention is to get the same results as o2scm.o2bas. I would need a little help about these issues:

In function alloc_cellseg (about line 496) I applied getmemory instead of malloc. Is there a place where I could use freememory too?

As goto can now be used globally, it should be possible to apply this statement instead of setjmp/longjmp? I assume this would be helpful for 64-bit compatibility, but at the moment I do not really know the results of longjmp. Perhaps Charles can give advice how goto can be used instead of longjmp.

There is another interesting aspect. If I apply: (load "ascii_mandel.scm") there will be an error message in about line 2355: "unable to car a non-pair element" and the app will crash. I suppose Error_0 must be checked.

Attached is OxyScheme.o2bas as a zip file. I commented the modifications with 'rs, the line numbering should almost be the same. If there are no objections, I would like to remove the prototypes of msvcrt.dll.

Roland


Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 02, 2019, 09:39:53 AM
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?
Title: Re: Updating OxyScheme
Post by: Arnold on November 03, 2019, 04:11:52 AM
Hi Mike,

thank you for your explanations. I wish I had that accuracy, too.

I always use the latest version of O2, in this case version: 0.2.8 2019-09-20T12:40:14.

After including corewin.inc I commented out the msvcrt.dll functions line by line, then always executed Oxyscheme.o2bas and O2scm.o2bas, loaded and executed the demo files to see if there is a different behaviour. So I found that there is a difference with _strlwr prototyped and unprototyped, but that I could also use lcase instead of _strlwr. I think built-in Oxygen functions should work a bit faster if they do not depend on msvcrt.dll?

Would it be okay if the comments will stay and setjmp/longjmp are not currently being tracked? So the functions could be uncommented if there is a differenc to O2scm.o2bas. But it would also be ok to comment out the protoyed funtions later.

Now I come to my weakness, which will hopefully not deter you. Although I have tried several times to better understand Scheme or Lisp, I have repeatedly failed. But I will continue until I understand the examples of Robbek and your examples. Oxyscheme (and Tinyscheme) will help me with that. Therefore, I am probably well suited to make any weird mistakes that can be made as a beginner.

At the moment simple errors like (1 + 1) will crash Oxyscheme / o2scm. I am wondering if it is possible to quickly discover the error that arises when loading ascii_mandel.scm (Error_0). Then probably already 99% of the problems are solved.

Roland
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 03, 2019, 04:59:00 AM
My friend,

Your OxyScheme.o2bas executed by older versions of OxygenBasic (e.g. 0.1.0 2019-02-03T20:36:03) seems to load and run flawlessly. Which means the crashes are not so much OxyScheme's but rather Charles' fault.

Quote
At the moment simple errors like (1 + 1) will crash Oxyscheme / o2scm.
;D

(1 + 1) is not a valid Scheme syntax. As can be seen in the screenshot below, OxyScheme successfully recovers from such typos flagging a corresponding error, and happily executes a valid statement (+ 1 1) instead.
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 03, 2019, 05:22:26 AM
Re. setjmp/longjmp: Yes, you can rem out the respective calls throughout the script but it may make full recovery from some (not all!) errors in the user .scm script or manual input impossible and crash-prone.

Re. built-in O2 functions: No, not necessarily. Though Charles' asm code is usually of very high quality, msvcrt.dll is also an extremely well optimized and time-proven piece of programming art. If both the runtime function and its O2 equivalent are implemented as functions, then the call and execution time will be the same if both implementations are of similar complexity. DLLs are mapped into the process memory, and calls to their functions are exactly as fast as calls to process main memory.

OTOH if Charles' intrinsics are implemented as asm macros, then they may really run faster because they would avoid the call overhead.
Title: Re: Updating OxyScheme
Post by: Arnold on November 03, 2019, 07:51:50 AM
Hi Mike,

luckily I have not yet deleted version 0.1.0, and you are right: O2scm.o2bas does not crash if I enter (1 + 1), it shows the error message and I will get the chance to enter (+ 1 1). Loading ascii_mandel.scm will give an error nevertheless but the app does not crash. Now perhaps it will be easier to find out what works differently.

I personally do not mind if something does not work as expected after an update of O2. I found so many older programs e.g. developed in C which cannot be compiled without modifications when using newer versions of e.g. TCC or Pelles C. In my opinion each new version of O2 offers new benefits, and in fact some of them I would really miss.

Roland
Title: Re: Updating OxyScheme
Post by: Arnold on November 05, 2019, 01:10:59 AM
Hi Mike,

I deleted the zip file of my first message. Probably you will not use it anyway. I was not aware that there is a different behaviour of o2scm.o2bas in version 0.1.0 and 0.2.8 of Oxygen. As long as it is not clear where the behavior deviates, it of course makes no sense to apply unprototyped functions.

Roland
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 05, 2019, 03:00:39 AM
Hi Roland,

I see. I think Charles has been very lucky to successfully maintain the script of such complexity for such a long time, practically throughout Oxygen's entire alpha phase. Now that beta is out that isn't supposed to basically change the way language features work (API/ABI-wise) any more, the script code may be finalized to fit both 32 and 64 bits.

But to do this, the programmer has to have a clear understanding of not only how Scheme works and what C features can best fit the language needs, but also how modern beta-stage Oxygen works. Regretfully, I didn't have sufficient spare time to follow the O2 development close enough to be able to cope with such a challenge ATM.
Title: Re: Updating OxyScheme
Post by: Arnold on November 05, 2019, 05:07:57 AM
Hi Charles, Mike,

this is what I have found so far, I do not know if it really helps. I simply set a debugflag in o2scm.o2bas and followed the error of (1 + 1). The app crashes in function token at the first expression:     
sys c = skipspace()

I am not sure if the logic for skipspace() in o2scm.o2bas has changed between 0.1.0 and 0.2.8? Is there a function in the include files of version 0.2.8 which could be compared?

This works in version 0.1.0 and would be the expected output for version 0.2.8:

...
equal?
do
unless
when
#<EOF>
> (+ 1 1)
2
> (1 + 1)
Error: illegal function

>
in sub token Enter new expression
> (+ 1 1)

in sub token
2
> (+ 1 1)
2
>


Roland 
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 05, 2019, 09:40:19 AM
Aha! This line needs to be altered:

Code: [Select]
  #define clearinput()      currentline = endline = linebuff

assignment operator within an expression :=

Code: [Select]
  #define clearinput()      currentline = endline := linebuff

Title: Re: Updating OxyScheme
Post by: Arnold on November 05, 2019, 11:25:08 AM
Thank you Charles. This was a very quick fix and the modification also worked for version 0.1.0. Although I studied Oxylog.txt several times I always overlooked your notes for 28/05/2019 (release 0.2.0). Maybe it is possible to create an error message for these cases? The rule should be clear, but careless mistakes will be unavoidable.

The adventure is not over yet. At the moment I investigate what happens after loading fib_fast.scm. (fibonacci 10) returns 1 which seems to be a bit too little. This will be a nice way to follow and study the code.

Roland
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 05, 2019, 03:25:21 PM
The compound assignment vs comparation change was made after this discussion:

https://www.oxygenbasic.org/forum/index.php?topic=1936.0

#4..#15
Title: Re: Updating OxyScheme
Post by: Arnold on November 06, 2019, 06:57:18 AM
Hi Charles, Mike,

I searched for some more compound assignments, perhaps I did not find all. Are my modifications correct, in particular line 555?

line 217:
#define clearinput()      currentline = endline := linebuff
line 555:
            args = envir := code := dump := NIL
line 1253:
    slow = fast := a
line 3344 - 3353
    car(NIL) = cdr(NIL) := NIL
    /* init T */
    flag(T) = (T_ATOM | DOMARK)
    car(T) = cdr(T) := T
    /* init F */
    flag(F) = (T_ATOM | DOMARK)
    car(F) = cdr(F) := F
    /* init EOF_OBJ */
    flag(EOF_OBJ) = (T_ATOM | DOMARK)
    car(EOF_OBJ) = cdr(EOF_OBJ) := EOF_OBJ

Attached is o2scm.o2bas as o2scm_mod.o2bas. At least I can now do something like:
(define y)

(write "Help") works, but (display "Help") does not work. What would be the best location in o2scm.o2bas for research?

Roland
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 06, 2019, 08:19:34 AM
Thanks Roland.

There is a missing *

in printatom

Code: [Select]
    else if (isstring(l)) then
      if (flg == 0) then
        p = cast char strvalue(l)
      else

should be

Code: [Select]
    else if (isstring(l)) then
      if (flg == 0) then
        p = cast char* strvalue(l)
      else


Title: Re: Updating OxyScheme
Post by: Arnold on November 06, 2019, 02:47:17 PM
Magnificent! This makes the difference between master and apprentice. I found printatom(), but I would never had found the cast char* solution. I will check the remaining cast cases too.

At the moment I try to find this difference:

> (if (= 10 0) (display "yes")
    (display "no"))
yes#t
>

The expected result is:
no#t
>

If I follow the code in o2scm.o2bas I end in about line 1535:
...
      case OP_IF1 /* if */
        if (istrue(value)) then
...

I am not sure if these two macros are still valid for newer versions of Oxygen:

  /* true or false value macro */
  #define istrue(p)  ((p) != NIL && (p) != F)
  #define isfalse(p) ((p) == NIL || (p) == F)

istrue and isfalse is used often in o2scm.o2bas but I do not yet know the expected result (1 or -1) and the values for nil, p and f. I will try to find this out tomorrow.
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 06, 2019, 07:28:50 PM
Hi Roland,

OxyScheme operators don't use direct literals (strings or numbers) for values or expression results. They rather operate on pointers to cell structures that resemble Variants in such languages as VB, VBA, FBSL, SB, etc. Cells can store numbers or strings in their corresponding member fields.

There are also four special cells to denote NIL, T, F, and EOF. Those don't have any specific numeric or string values. Instead, if some OxyScheme value or expression result points to such a cell, the value/result is considered equal to the corresponding special "value".

In fact, only one expression -- (quit) -- is expected to return a valid NIL explicitly, in which case the session Eval_Cycle loop should break and OxyScheme should exit its prompt altogether, which it currently doesn't. There seem to be some more expressions (presumably in nsinit.scm) that return an erroneous NIL that breaks Eval_Cycle prematurely on app start.

So in those equivalence macros, NIL, T, F stand for pointers to the respective special cells, and p stands for the pointer to the value cell being evaluated.

Otherwise, the O2 source code of OxyScheme uses C-style !0 (i.e. not equal to 0) as the value of TRUE throughout the entire script.
Title: Re: Updating OxyScheme
Post by: Arnold on November 07, 2019, 12:53:40 AM
Hi Mike,

thank you. Your source code is full of refinements. I am glad I did not try to understand o2scm.o2bas when you provided it, this would have been far beyond my abilities. In the meantime I reinstalled a distro of 2015 (A41) where I can execute o2scm.o2bas with #autodim off to compare the results. There are only minor changes in the current version of o2scm.o2bas, O2 is a bit stricter now, so I think it should be possible to find out the few differences.

I see that you created a type cell and use pointer arithmetic to store and fetch values to / from the members. Now that Oxygenbasic can handle types as parameters, maybe it makes sense to use this possibility? But right now this aspect is not that important.

Roland
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 07, 2019, 03:35:38 AM
The OxyScheme code is a spitting image of its C prototype, and is therefore not very common to how it would look were it written in BASIC from scratch. Almost all ANSI C features can be implemented in O2 relatively easily but not vice versa. If we augment the O2 code with Oxygen-specific options, it will deviate from the prototype too far to be back-portable to FBSL's nanoscheme written in ANSI C and won't thus be usable for direct comparison purposes any more.
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 07, 2019, 02:05:32 PM
Hi Mike,

I wonder if NIL and F could be made identical safely. It would simplify the internal logic.
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 07, 2019, 02:10:06 PM
Hi Roland,

The definitions for istrue and isfalse require some extra brackets for explicit operator precedence

Code: [Select]
  #define istrue(p)  (((p) != NIL) && ((p) != F))
  #define isfalse(p) (((p) == NIL) || ((p) == F))
Title: Re: Updating OxyScheme
Post by: Arnold on November 07, 2019, 06:41:28 PM
Hi Charles,

I knew you already told me this and I finally found the link:

Macros as Functions: #return
https://www.oxygenbasic.org/forum/index.php?topic=1536.msg18180#msg18180

but then I had to interrupt. With your fix istrue / isfalse should work correctly in newer versions of Oxygen.

Now fib_fast.scm will return the correct results. Unfortunately garbage collection will crash o2scm. The app will crash in sub mark. I tried to follow the code with some print statements:

Code: [Select]
  sub mark(sys a)
  ===============
    sys t, q, p
printl "in sub mark"   
    t = 0
    p = a
E2:
printl "in E2"
    setmark(p)   
    if (isatom(p)) then goto E6
    q = car(p)
    if ((q != 0) && (ismark(q) == 0)) then
      setatom(p)
      car(p) = t
      t = p
      p = q
      goto E2
    end if
E5:
printl "in E5"
print ",t = " t "  --- Enter: " : waitkey
    q = cdr(p)
    if ((q != 0) && (ismark(q) == 0)) then
      cdr(p) = t
      t = p
      p = q
printl "from E5 to E2"     
      goto E2
    end if
E6:
printl "in E6"
print ",t = " t
    if (t == 0) then exit sub
    q = t
    if (isatom(q)) then
      clratom(q)
      t = car(q)
      car(q) = p
      p = q
 printl "from E6 to E5"     
      goto E5
    else
      t = cdr(q)
      cdr(q) = p
      p = q
printl "from E6 to E6" ': waitkey     
      goto E6
    end if
  end sub

Mark() will never exit the sub in E6: and will crash in E5: after some time. The procedure must be checked a bit more. But it is a bit late now and I have to take a little break.

Roland

This is a sample output:

> (load "fib_fast.scm")
loading fib_fast.scm
fibo*
fibonacci
#<EOF>
> (fibonacci 100)
gc start ...
in sub mark
in E2
in E2
in E2
in E6,t = 137595348
from E6 to E6
in E6,t = 5510696
from E6 to E5
in E5,t = 5510696  --- Enter:
in E6,t = 5510696
from E6 to E5
in E5,t = 137595348  --- Enter:
in E6,t = 137595348
from E6 to E6
in E6,t = 137595336
from E6 to E5
in E5,t = 137439027  --- Enter:        ==> crash


Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 07, 2019, 08:29:57 PM
Hi Charles,

No, F and NIL cannot be made identical because they denote different entities. One and the same boolean expression may return either F or NIL (e.g. in case a parameter is faulty or missing and the corresponding error isn't intercepted).

F refers to a value that resolves/amounts to 0/FALSE in math and boolean expressions. (T refers to any value except numeric 0 or boolean F)

NIL refers to an object that denotes an empty list, i.e. ().

You may regard NIL as a rough equivalent of ScriptBASIC uninitialized undef.
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 07, 2019, 08:54:38 PM
Hi Roland,

Fibonacci is a deeply recursive function that exhausts the program stack very quickly. Interpreters (and Scheme is an interpreter) usually have a rather shallow preallocated program stack, which leads to its exhaustion, and hence, crash at large Fibonacci numbers.

A reasonable (and visibly slow to calc) limit to the argument would be (fibonacci 28) or smaller.

Please check if that value would still crash the garbage collector and let us know your results.
Title: Re: Updating OxyScheme
Post by: Arnold on November 08, 2019, 02:43:40 AM
Hi Mike,

with my machine after running o2scm.o2bas with O2 I can calculate (fibonacci 60) after loading fib_fast.scm (load must be the first command). The next input e.g. (fibonacci 5) will lead to gc_start (3 * Enter and crash).

#<EOF>
>  (load "fib_fast.scm")
loading fib_fast.scm
fibo*
fibonacci
#<EOF>
> (fibonacci 60)
2504730781961
> (fibonacci 5)
gc start ...
in sub mark
...

With o2scm in A41 I can calc up to (fibonacci 91). If I add in sub init_globals() like in the version of 0.2.8:
gc_verbose = 1

then I will also see gc_start when garbage collection begins:
> (fibonacci 91)
gc start ... done: 12948 cells recovered.
7540113804746346429

Btw: the values seem not to be correct with bigger numbers? Using two different online calculators I found these results:
fibo 60 =         1.548.008.755.920
fibo 91 = 4.660.046.610.375.530.309

fibo 28: fib_fast.scm in o2scm=514229, fib_fast.scm in in Tinyscheme: also 514229, online calc=317811. But at the moment I do not know the correct answer.

Roland
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 08, 2019, 07:20:45 AM
Roland,

Re. fib & fib_fast calc: Your online calc seems to be wrong. Both fib and fib_fast display 5142292504730781961, and (almost) 7540113804746346429 when run in online Scheme compilers for 28, 60, and 91, respectively. (see below)

Re. large Fibonacci numbers: OxyScheme registers and its display (in fact, print) routine handle only up to 64 bit-long numbers (long long ints and double-precision reals). If any intermediate calc involved in obtaining the final result overflows, then the final result is going to also be wrong. There is currently no error flagging of register and/or value overflow.
Title: Re: Updating OxyScheme
Post by: Arnold on November 08, 2019, 09:33:03 AM
Thank you, Mike. I think this is a helpful info, because I can now assume that most of the routines work similar in o2scm.o2bas of version 0.2.8 compared to o2scm_03_2015.o2bas of version A 41.

I added the same print statements in o2scm.o2bas of A41. A 41 will not crash after the 3rd waitkey. If I comment out the waitkey statement, I can see that garbage collection will succeed after many cycles.

With A41 the flow is: E2,E2,E2,E6, E5,E6, E5,(t=0),E2,E2,E2,E6,E5 etc.
With version 0.2.8   : E2,E2,E2,E6, E6,E5, E6         ,E5,E6,E6,E5    crash

I am a bit confused about the value of t in E6 (t in v0.2.8 is about 10 times bigger than t in A 41). The flow of A41 is also different after E6 compared to v0.2.8. Does clratom or another macro in sub mark() work differently?

Roland

Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 08, 2019, 10:26:57 AM
Scheme's program stack is in fact a linked list of cells that comprise:
-- a flag to denote a used cell's type, or a mark for garbage collection, or a free cell;
-- two unions to store string or numeric values; and
-- two address fields (_car and _cdr) to point to the preceding and next cells, respectively, in the doubly linked list.

What GC does is iterate through the entire linked list following each cell's _car and _cdr pointers to spot cells marked with a flag for garbage collection, clear their values and flags, and possibly rearrange the newly freed cells into contiguous blocks of program free memory by changing their _car and _cdr pointers to the adjacent (closest) free cells.

I'd suggest asking Charles to check if the garbage collection routines (all of them) that use pointer access, for compliance with modern O2 pointer notation.

The difference in t values should not bother you much because it is a temporary pointer value that depends on which program memory cell exactly the garbage collector is currently dealing with. Since different builds of O2 are very likely to allocate program memory in different areas of RAM, the pointer values are going to differ accordingly.
Title: Re: Updating OxyScheme
Post by: Arnold on November 08, 2019, 01:22:38 PM
Somehow I think, that some of the #define macros starting at about line 164 might need extra brackets like the istrue / isfalse macros? But if this should be the case, I have no idea at the moment how to proceed to verify this.
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 09, 2019, 04:24:27 AM
The problem occurs with macros used inside an expression, and I did not see any others requiring extra brackets. I should be able to fix this in o2  by passing all the macro sources through the 'precedenter ' before storing.

But istrue and isfalse can be implemented more efficiently by using asm calls:

Code: [Select]
  '#define istrue(p)  (((p) != NIL) && ((p) != F))
  '#define isfalse(p) (((p) == NIL) || ((p) == F))
  #define istrue(p) call istrue_asm(p)
  #define isfalse(p) call isfalse_asm(p)

 ... 'append to o2 asm helper functions

.istrue_asm
  mov eax,0
  mov ecx,[esp+4]
  (
    cmp ecx,NIL
    jnz exit
    ret 4
  )
  (
    cmp ecx,F
    jnz exit
    ret 4
  )
  mov eax,-1
ret 4

.isfalse_asm
  mov eax,-1
  mov ecx,[esp+4]
  (
    cmp ecx,NIL
    jnz exit
    ret 4
  )
  (
    cmp ecx,F
    jnz exit
    ret 4
  )
  mov eax,0
ret 4
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 10, 2019, 03:42:16 AM
Comparing Scheme code with Basic code:

Code: [Select]
'12:44 09/11/2019
'sheme and basic compare
'(define fibo*
'   (lambda (a b x)
'     (if (= x 0) a
'        (fibo* b (+ a b) (- x 1)))))
'
function fibo(int a,b,x) as int
  if x=0 then return a else return fibo(b,a+b,x-1)
end function
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 10, 2019, 04:18:25 AM
Hehe that's too simple an example indeed, Charles!

But what would you do with complex lists or lists of lists as arguments to a lambda? ;)
Title: Re: Updating OxyScheme
Post by: Arnold on November 10, 2019, 08:58:32 AM
Hi Charles, Mike,

at least I learned this little trick with o2scm.o2bas:

Code: [Select]
uses corewin

function fibo(quad a,b,x) as quad
  if x=0 then return a else return fibo(b,a+b,x-1)
end function

quad x = fibo(1,1,91)
' print x

char s[30]
sprintf(s, "%I64d", x)
print s

Btw: MSDN states for _strlwr, etc:

Return Value
Each of these functions returns a pointer to the converted string. Because the modification is done in place, the pointer returned is the same as the pointer passed as the input argument. No return value is reserved to indicate an error.
...
If str is a NULL pointer, the invalid parameter handler is invoked, as described in Parameter Validation. ...

Does _strlwr create side effects in o2scm.o2bas? If I use the function unprototyped I get an error e.g.: unbound variable 35467044

Roland
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 10, 2019, 10:34:04 AM
Do strlwr() and _strlwr() produce similar test printf() printouts when used in the OxyScheme code?

Does unprototyped strlwr() work as expected? If yes then why bother changing it to anything else?
Title: Re: Updating OxyScheme
Post by: Arnold on November 10, 2019, 12:49:10 PM
Hi Mike,

I only would like to find a reason why mark(oblist) in sub gc() does not work like in A41. Until now I can see that in A41 function atoll() was used and substituted later, strcmp was applied a bit differently with some push and mov statements and I wonder if _strlwr can play a role. For my test with o2scm of 0.2.8 I do not use nsinit.scm. I added two print statements in case OP_EVAL in about line 1390:
...
          else
printl "oblist: " oblist : printl         
            Error_1("unbound variable", code)
and in about line 1404:
...
        end if
printl "oblist: " oblist : printl
        s_return(code)
       
      case OP_E0ARGS /* eval arguments */
...

If I run o2scm with _strlwr prototyped, I get this result:
Error: unable to open "nsinit.scm"

> (define x)

oblist: 137819936
x
>

If I use _strlwr unprototyped:
  ! _strlwr             '(char* a) as char*

then I get this result:
Error: unable to open "nsinit.scm"

> (define x)

oblist: 134477528
Error: unbound variable 34035020

I do not know if this matters in any way, but I feel obliged to report the different behaviour. I am simply confused that garbage collection runs differently in A41. Garbage collection did already not work in version A43.

Roland
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 10, 2019, 02:57:15 PM
Hi Roland,

Re. nsinit.scm: This file contains a library (not complete yet!) of high-level macros (syntax extensions) written in the Scheme language and required as per R5RS. Without this library, you won't be able to run scripts more complicated than this rudimentary Fibonacci calc.

I wouldn't try to debug or test a program that signals an error without first fixing that error. OxyScheme usually recovers fully from all the errors it reports, but who knows... (why wouldn't you let the app load that library, after all?)

Re. value of oblist: This is a pointer to the symbol table, i.e. to the first cell in a linked list of cells that stores the names used in the language syntax, and therefore its exact value is dependent on how this particular program image is arranged in the computer RAM. The value per se is of very little use for bug tracking or anything else.

Re. 34035020: This number looks pretty much like a pointer. I think either an unprototyped _strlwr cannot treat its argument as a char* because O2 wouldn't pass it by ref (more likely) or else O2 cannot accept the _strlwr return as a char* (less likely). In which cases the function or O2 would simply default to treating the argument or return, respectively, as a mere integer value converted to a string literal. Then OxyScheme would flag it as an unbound (i.e. undefined in the code) variable.

Re. atoll: The original TinyScheme code was written to be compiled with GCC. atoll() is a Linuxoid function not available in Microsoft's msvcrt.dll runtime. So, Charles (or I?) wrote an asm macro atoll_asm to emulate this function in O2. Later on, somebody (presumably Charles again, judging by the single-quoted rem) found an original _atoi64() equivalent to atoll() in msvcrt.dll and changed the source code.

But both _atoi64() and _i64toa() use and return VC long long integers, not O2 64-bit floating point quads! Charles, please comment here whether O2 currently makes an equivalent substitution of quads in its integer registers automatically and transparently when it pushes and receives 64-bit integers to/from a DLL?

If Charles says yes, then I think such functions cannot be used unprototyped because Oxygen simply wouldn't know what integer arguments (32- or 64-bit) to push when calling the functions or what registers to use when fetching their return.
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 10, 2019, 05:12:11 PM
Quote
But both _atoi64() and _i64toa() use and return VC long long integers, not O2 64-bit floating point quads! Charles, please comment here whether O2 currently makes an equivalent substitution of quads in its integer registers automatically and transparently when it pushes and receives 64-bit integers to/from a DLL?

Yes, I confirm that extern functions returning quads use the edx:eax register pair in 32bit mode. And prototype definitions are necessary when returning quads.

For 64bit compiling of o2scm, I  would suggest overriding quad completely:
typedef sys quad
then you wont need dll prototypes, (and you won't be using cdecl anywhere).
Title: Re: Updating OxyScheme
Post by: Arnold on November 11, 2019, 06:22:54 AM
Charles example of fibo.o2bas inspired me to do this with kings_reward.o2bas too (but it does not look like Scheme):

Code: [Select]
uses corewin
uses console

sub grains(int x)
    int i
    quad j = 1
    char s[20]

    for i = 1 to x
       printl " field " i ":   number of grains:  "
       sprintf(s, "%I64u", j)
       print s
       j *= 2
    next
end sub   

printl " The reward of the King"
printl " ----------------------" + cr
grains 64

printl "Enter ..."
waitkey

I found the "%I64d" and "%I64u" format-strings for sprintf interesting. There are some more sprintf examples in \examples\Msvcrt\ and in o2tests.o2bas which can be possibly applied.
Title: Re: Updating OxyScheme
Post by: Arnold on November 23, 2019, 02:30:21 AM
Hi Charles, Mike,

is there a chance to find out why 'when' of nsinit.scm does not work? (it ran ok with o2scm.o2bas of version A41).

This does work:

(cond ((> 3 2 ) ' greater))   --> greater
(cond ((< 3 2 ) ' greater))   --> ()
      
This does not work in version 0.2.8:

(when (> 3 2) 'greater)     --> Error: unbound variable unquote
(when (< 3 2) 'greater)     --> Error: unbound variable unquote

Unfortunately it is very difficult to trace the source-code due to the many macros.

Roland
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 23, 2019, 05:07:14 AM
Hi Roland,

when is not included in the current o2scm.o2bas or the R5RS manual.

But it is used in Racket:
https://docs.racket-lang.org/reference/when_unless.html
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 23, 2019, 05:47:57 AM
Charles, Roland,

Both when and unless are included in the current version of OxyScheme as Scheme macros defined in nsinit.scm. It is true they aren't part of R5RS. But both of them were defined in the later R6RS recommendation that was emerging at the time the o2scm.o2bas script was developed. Their implementation and syntax are simpler than those of cond, so why not include them if we can?

The macros work well in both the older OxyScheme and its FBSL nanoscheme prototype, so I presume they'll be usable again if and when other minor differences between the old and new O2 notation are tackled with.
Title: Re: Updating OxyScheme
Post by: Arnold on November 23, 2019, 05:56:05 AM
Hi Charles,

I found 'when' in nsinit.scm of Oxygenbasicprogress.zip. As Mike stated it is defined as a macro at the bottom of nsinit.scm:

;; when
(macro when (lambda (form)
     `(if ,(cadr form) (begin ,@(cddr form)))
))

The macro is used in kings_reward.scm. I noticed the misbehaviour when I applied: (grains 4) and the loop did not end. Most curiously no error is displayed when running the script. I can define the macro in 0.2.8 and call it:

>when
#<CLOSURE>

but it seems I cannot use the macro. I must admit that I do not know how to test the '(if .. part of the macro and use this instead of when in kings_reward.scm

Roland
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 24, 2019, 06:47:41 AM
Do we have some more elementary examples of Scheme macros? The syntax is not clear.
Title: Re: Updating OxyScheme
Post by: Arnold on November 24, 2019, 07:21:22 AM
Hi Charles,

sometimes I am completely blind. By rereading my last message and comparing with o2scm of A41 I noticed that entering when should give this result:
<macro> instead of <closure>. Macros of nsinit.scm are: quasiquote, do, unless and when.

Something must run differently in o2scm.o2bas of 0.2.8 at the moment. The app confuses macro with closure.

Roland
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 24, 2019, 10:39:53 AM
Hi Roland,

when and the other macros all yield #<MACRO> in the FBSL nanoscheme equivalent of O2 OxyScheme.

As I mentioned earlier, nanoscheme was a little more advanced, and better debugged, than OxyScheme, and I admit that therefore OxyScheme might not be 100% compatible when I quit working on it because some forum members were clearly against "promoting" the alien language on a BASIC forum.

Thus, rendering OxyScheme fully compliant may take some more effort than just updating the O2 pointer notation. First of all, the cell structure itself should be made fully equivalent to C-language

struct cell{
    unsigned long _flag;
    union {
      struct {
        char* _svalue;
        long  _keynum;
      } _string;
      struct {
        union {
          __int64 _ivalue;
          double  _rvalue;
        } _value;
      } _number;
      struct {
        struct cell* _car;
        struct cell* _cdr;
      } _cons;
    } _object;
  } cell;

rather than its O2 palliation

  type cell
    sys _A    // placeholder
    sys _B    // placeholder
    sys _flag // type of cell
  end type


that was the only feasible way to declare that structure in an ancient O2 that had no unions nor genuine I64 data type at the time the translation was made.

I think the person who will happen to be able to make the OxyScheme code fully compliant to at least its nanoscheme prototype, let alone TinyScheme and/or R5RS, may definitely call himself proudly a "language developer". :D
Title: Re: Updating OxyScheme
Post by: Arnold on November 25, 2019, 06:24:04 AM
Hi Mike,

Oxyscheme worked pretty well with O2 version A41, and probably there are only minor issues currently.

I myself have lowered my goals a bit at the moment, but I intend to benefit from the tricks of o2scm.o2bas as much as possible. I found an older minischeme.c (which only applies integers) that uses a similar cell structure as the one you introduced. I added TOK_EOF, EOF_OBJ and some modifications. I can compile the file with tcc and gcc to 32-bit and 64-bit. So I think it will be a good starting point for me in many aspects. The main aspect is the learning experience.

Roland

Code: [Select]
/*      ---------- Mini-Scheme Interpreter Version 0.85 ----------
 *                coded by Atsushi Moriwaki (11/5/1989)
 *  This version has been modified by Chris Pressey.
 *    current version is 0.85 mod (as yet unreleased)
 *  This version has been modified by R.C. Secrist.
 *  This is a revised and modified version by Akira KIDA.
 
 *               THIS SOFTWARE IS IN THE PUBLIC DOMAIN
 *               ------------------------------------
*/
// only for Windows, tested with Win10
// added TOK_EOF, EOF_OBJ, OP_GENSYM, some other modifications
// works with "msinit.scm"
...

Edit:

I noticed that the 'do' macro did not work due to a missing gensym procedure. Therefore I added OP_GEN of o2scm.o2bas. The attached zip file contains miniscm.c, msinit.scm, Test_Cases.scm. Also added a 32-bit executable compiled with the gcc compiler of mingw.
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 25, 2019, 10:17:48 AM
This simplified version of when works in oxycheme, so macros are basically ok:

Code: [Select]
(macro when (lambda(a b) (cond (a b) ) ) )

(when (> 2 1) 'greater )

Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 25, 2019, 07:45:33 PM
Roland,

The nano-/oxyscheme code was based (with some amendments of mine) on a slightly different, more precise and arguably a little faster, version 0.85k4 of same:

/*
 *      ---------- Mini-Scheme Interpreter Version 0.85 ----------
 *
 *                coded by Atsushi Moriwaki (11/5/1989)
 *
 *            E-MAIL :  moriwaki@kurims.kurims.kyoto-u.ac.jp
 *
 *               THIS SOFTWARE IS IN THE PUBLIC DOMAIN
 *               ------------------------------------
 * This software is completely free to copy, modify and/or re-distribute.
 * But I would appreciate it if you left my name on the code as the author.
 *
 */
/*--
 *
 *  This version has been modified by R.C. Secrist.
 *
 *  Mini-Scheme is now maintained by Akira KIDA.
 *
 *  This is a revised and modified version by Akira KIDA.
 *   current version is 0.85k4 (15 May 1994)
 *
 *  Please send suggestions, bug reports and/or requests to:
 *      <SDI00379@niftyserve.or.jp>
 *--
 */


The code then got promoted by Dimitrious Souflis yet further to 32-bit only and still public domain v1.41 that became completely thread safe:

/* T I N Y S C H E M E    1 . 4 1
 *   Dimitrios Souflis (dsouflis@acm.org)
 *   Based on MiniScheme (original credits follow)
 * (MINISCM)               coded by Atsushi Moriwaki (11/5/1989)
 * (MINISCM)           E-MAIL :  moriwaki@kurims.kurims.kyoto-u.ac.jp
 * (MINISCM) This version has been modified by R.C. Secrist.
 * (MINISCM)
 * (MINISCM) Mini-Scheme is now maintained by Akira KIDA.
 * (MINISCM)
 * (MINISCM) This is a revised and modified version by Akira KIDA.
 * (MINISCM)    current version is 0.85k4 (15 May 1994)
 *
 */


And (hopefully) finally, John had me sweet-talked into extending that later tinyscheme code to 64 bits, which we did (hopefully again) successfully totally outside the framework of OxygenBasic forum. :D


Charles,

But regretfully, your simpler implementation fails miserably in FBSL C nanoscheme, original C minischeme and multithreaded 32-bit tinyscheme complaining invariably of insufficient arguments/parameters to the macro. Which, alas, invalidates your implementation as a reference. :-[
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 26, 2019, 02:54:52 AM
Hi Mike,

I was just trying to isolate the problem. It appears to be in the unquote procedures ','

this wont work:

Code: [Select]
`(list ,(+ 1 2) 4)
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 26, 2019, 08:09:33 AM
Yes Charles,

Your diagnosis seems correct. Oxyscheme doesn't recognize unquote flagging it erroneously as an unbound variable.

Quote/unquote should just render the entire statement that follows, as a string literal, rather than execute that statement immediately. They are part of macro notation used chiefly to embed macro implementations in Scheme libraries. Once the library is loaded, and its embedded macro implementations, unquoted, executed where necessary and mapped in the process memory, the respective macros may be used by their names as ordinary pieces of executable code throughout a Scheme program.
Title: Re: Updating OxyScheme
Post by: Arnold on November 26, 2019, 08:24:21 AM
Perhaps backquote does not work correctly?
 `(+ 2 3)   expected: (+ 2 3)
Error: unable to cdr a non-pair element

This is also a nice construct:
 `,(+ 2 3)  exptected: 5
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 26, 2019, 08:35:08 AM
Yes Roland,

In both cases, FBSL nanoscheme produces the effects as you'd expect. But oxyscheme regretfully falters, which means not only unquote but also quasiquote fail in the O2 environment.

Cutting it short, oxyscheme is in need of serious overhaul even in an older Oxygen before it ever goes 64 bits. :(
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 26, 2019, 07:40:17 PM
I'm giving it the full sweep. I've found a few indexing anomalies so far, which might explain the quote/unqute problems.
Title: Re: Updating OxyScheme
Post by: Charles Pegge on November 27, 2019, 07:55:59 AM
How might you bind Scheme to Windows and other APIS?
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on November 27, 2019, 08:37:52 AM
There are a few Lisps around that have bindings to Windows graphics and API. We can look up and mimic their semantics to keep up the letter and spirit of this near-esoteric language cluster.

When I'm looking into those weird Scheme-ish scripts, it feels as if I'm trying to follow simplified Chinese. ;D
Title: Re: Updating OxyScheme
Post by: Arnold on December 05, 2019, 02:04:41 AM
Hi Mike,

is there a way to check some test cases with miniscm.exe / o2scm.o2bas? Due to my lack of knowledge, I currently do this:

Code: [Select]
;; simple test cases

(define CheckResult
  (lambda (num  expected)
     (display "Test ")
     (display num)
     (display " Expected: ")
     (display expected)
     (newline)
     ))

; (display ", result: ")
; (display result)

...


Is there a way to store e.g. the result of Test 1 (#CLOSURE) or the results of the other tests in a variable and compare this with the expected value? I just want to show the differences. This would save some time.

Roland
Title: Re: Updating OxyScheme
Post by: Arnold on December 05, 2019, 06:05:36 AM
In the meantime I found a slightly better solution:

Code: [Select]
;; simple test cases

(define result)

(define CheckResult
  (lambda (num  result expected)
       (if (equal? result expected ) (begin (display "Test: ")
                                            (display num) (display " ok "))
         (begin
           (display "Test ") (display num) (display ", result: ") (display result)
           (display " Expected: ") (display expected)
           (newline)))
     ))

...

Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on December 06, 2019, 02:18:15 AM
Hi Roland,

In fact, there are many relatively simple ready-made unit test suites for Scheme, e.g. this one (http://community.schemewiki.org/?bunny-test). Just load The Code section as an .scm file (it contains the suite's base defines) and then follow the instructions to actually design and run simple unit tests. The test suite syntax should be fully compatible with oxy-/nano-/mini-/tiny-/Schemes. :)
Title: Re: Updating OxyScheme
Post by: Arnold on December 07, 2019, 12:19:34 PM
Thank you Mike for the link. I will certainly investigate more about this topic. For the moment I am applying a very simple approach which only checks the results:

Code: [Select]
;; simple test cases

(define TestResult)
(define tmpTestResult)
(define FailedCases)
(define Counter 0)

(define CheckResult
  (lambda (num  TestResult Expected)
       (if (equal? TestResult Expected )
          (begin (for-each display (list "Test: " num " ok ")))
        ;else
          (begin
             (for-each display (list "Test: " num ", Result: " TestResult " Expected: " Expected))
             (newline)
             (set! Counter (+ Counter 1))
             (set! FailedCases (append FailedCases (list num TestResult Expected))))
       
     )))

 
(define ReportFailures
  (lambda (Counter)
     (if (= 0 Counter)
        (display "All Tests passed OK")
     ;else
        (begin
        (display Counter) (display " Test(s) failed")
        (newline)
        (display FailedCases)
        (newline)
      ))))
   
   
;;; lambda
;;;; syntax:  (lambda formals body)

;1
(set! tmpTestResult `,(lambda (x) (+ x x)))       ;(CheckResult  1   TestResult  `"#<CLOSURE>" )
(set! TestResult `,(closure? tmpTestResult))      (CheckResult  1   TestResult  `#t )

;2
(set! TestResult `,((lambda (x) (+ x x)) 4))      (CheckResult  2   TestResult  8 )

;3
(define reverse-subtract
  (lambda (x y) (- y x)))
(set! TestResult `,(reverse-subtract 7 10))       (CheckResult  3  TestResult 3 )

;4
(define add4
  (let ((x 4))
    (lambda (y) (+ x y))))
(set! TestResult `,(add4 6))                      (CheckResult  4  TestResult 10 )

;5
(set! TestResult `,((lambda x x)
  3 4 5 6))                                       (CheckResult  5  TestResult '(3 4 5 6) )

;6
(set! TestResult `,((lambda (x y . z) z)
  3 4 5 6))                                       (CheckResult  6  TestResult '(5 6) )

;7
(set! TestResult `,(= 10 0))                      (CheckResult  7 TestResult `#f)

;Test function
;8
(define factorial
  (lambda (n)
    (let fact ((i n))
      (if (= i 0)
          1
          (* i (fact (- i 1)))))))
(set! TestResult `,(factorial 12))                (CheckResult  8  TestResult 479001600 )


(newline)
(ReportFailures Counter)
(newline)
(display "End of tests")

When I know more about Scheme I would like to format the output of failed cases.

I noticed that miniscm.c of my reply #44 does not work correctly with applying the 'do' macro due to a missing gensym procedure. Therefore I added OP_GENSYM and autogen() of o2scm.o2bas and updated the attachment of reply #44. I have also created a msinit.scm with some more definitions, as miniscm does not include all the capabilities of o2scm. But it is interesting to compare miniscm.c with o2scm.o2bas and see all the items which are missing.
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on December 07, 2019, 05:28:32 PM
Roland,

minischeme/msinit had been designed to comply with R4RS and was written long before R5RS emerged. The later R5RS introduced a macro language that enabled much more elaborate macros to be designed and included as standard library extensions.

The Lisp/Scheme community turned out to be much wiser and farseeing than BASIC in sponsoring regular language developer conferences to work out guidelines and recommendations along which the community would like to see their languages developed. Conversely, the BASIC community proved itself a stagnant swamp in this regard floundering in the dialects that had very little to offer beyond troglodyte Dartmouth.
Title: Re: Updating OxyScheme
Post by: Aurel on December 08, 2019, 04:59:05 AM
sponsoring regular language developer
sponsoring  with what ?
..and where are all that friendly lisp/scheme/..and dialects community
i really doubt that people who visit this forum take care about lisp/scheme
but that is just me ..the stupid hobby basic-only so called programmer ..he he
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on December 08, 2019, 07:46:59 AM
Aurel,

There are at least three, possibly four (taking John into consideration), people who care about Lisp/Scheme on this forum: Charles, Roland, and myself.

And there is but one person who doesn't -- and that's you.

At any rate, we're talking about OxyScheme -- a product that's been written in OxygenBasic, and as any other O2 product, it has every right to be discussed here as long as there's at least one person willing to do so.

(I thought after all these years, you grew to know better than spam the OxyScheme threads like you did in the past.)
Title: Re: Updating OxyScheme
Post by: Charles Pegge on December 10, 2019, 04:34:20 AM
I don't see core Scheme as a complete programming language, but I'm interested in a compilable Scheme, with the few necessary extensions to work directly with DLLs, (and to perform loops without recursion!).

example:
http://matt.might.net/articles/compiling-scheme-to-c/
Title: Re: Updating OxyScheme
Post by: jack on December 10, 2019, 11:35:39 AM
hello Charles
Racket compiles to executable, though I only lightly touched it.
https://www.racket-lang.org/
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on December 10, 2019, 12:07:14 PM
Charles,

Core Scheme seems as much abortive as a console-only BASIC and is therefore of limited interest only these days. Yet as I said, there are a number of Scheme implementations (mainly Linuxoid) that offer both dynamic library linking capabilities and GUI front-ends. What's more, their semantics is capable of interfacing Scheme apps with 3rd party OOP code and objects.

One such implementation is Bigloo (https://pdfs.semanticscholar.org/4127/62582c8b78d290f9a7a6a17de3e904b89249.pdf?_ga=2.83949593.1299548058.1576010537-815141885.1576010537). It's an established dialect whose binding grammar can be duplicated in OxyScheme to reimplement similar features in it as needed.

As far as loops are concerned, R5RS defines at least two looping macros, for-each and do, that has both been implemented in OxyScheme too -- see nsinit.scm. (though I'm not sure how functional the macros are now) Granted they are not exact replicas of their C/O2 counterparts, but in many cases they allow us to write code much more similar to that of procedural languages than Lisp-ish/Scheme-ish recursion.
Title: Re: Updating OxyScheme
Post by: John on December 10, 2019, 12:58:39 PM
Recursion is like waiting for the top to stop.
Title: Re: Updating OxyScheme
Post by: Charles Pegge on December 10, 2019, 03:45:22 PM
The do macro  :o

I think this tortuous code is a symptom indicating that loops should have been built into core Scheme.

Code: [Select]
(macro do
  (lambda (do-macro)
    (apply (lambda (do vars endtest . body)
             (let ((do-loop (gensym)))
               `(letrec ((,do-loop
                           (lambda ,(map (lambda (x)
                                           (if (pair? x) (car x) x))
                                      `,vars)
                             (if ,(car endtest)
                               (begin ,@(cdr endtest))
                               (begin
                                 ,@body
                                 (,do-loop
                                   ,@(map (lambda (x)
                                            (cond
                                              ((not (pair? x)) x)
                                              ((< (length x) 3) (car x))
                                              (else (car (cdr (cdr x))))))
                                       `,vars)))))))
                  (,do-loop
                    ,@(map (lambda (x)
                             (if (and (pair? x) (cdr x))
                               (car (cdr x))
                               nil))
                        `,vars)))))
      do-macro)))
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on December 11, 2019, 02:09:07 AM
Hehe, unlike anarchist BASICs, Scheme dialects are not allowed to expand the language core vocabulary at the developer's volition. Standard library extensions are supposed to first stay in the library in the form of macros for years if not decades to get their functionality (as set forth by RnRS recommendations) and usefulness field-proven by the community. Implementations may differ from dialect to dialect but not the interface or place in the language keyword hierarchy.
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on December 11, 2019, 02:20:43 AM
BTW let me note again that oxy-/nano-/mini Schemes are not yet fully R5RS compatible as-is. They still lack vector (= array) and char data type functionality. I lost interest in developing the code before I had a chance to add those features to the core language.
Title: Re: Updating OxyScheme
Post by: Charles Pegge on December 14, 2019, 03:54:52 AM
Before the PC, every home computer had its own hardware, and came with its own built-in version of BASIC and integral operating-system. So diversity was there from the start :)

However R5RS Scheme is, in my view, an incomplete language, so the standardisation is a bit of a cheat.

I would like to see how Scheme would encode a Windows GUI app.
Title: Re: Updating OxyScheme
Post by: Mike Lobanovsky on December 14, 2019, 02:02:48 PM
I can recollect vaguely the late Robbek used to upload a few Lisp apps here bundled with some GUI framework DLL that hung in memory so tightly we had to use the Task Manager to kill the process...
Title: Re: Updating OxyScheme
Post by: John on December 15, 2019, 09:27:43 PM
IUP has a Lisp binding (https://github.com/lispnik/iup).

Code: Lisp
  1. ;;; Generated from org-mode, do not edit
  2.  
  3. (eval-when (:compile-toplevel :load-toplevel :execute)
  4.   (ql:quickload '("iup" "iup-scintilla")))
  5.  
  6. (defpackage #:iup-examples.dialogs
  7.   (:use #:common-lisp)
  8.   (:export #:dialogs))
  9.  
  10. (in-package #:iup-examples.dialogs)
  11.  
  12. (defun dialogs ()
  13.   (iup:with-iup ()
  14.     (iup-scintilla:open)
  15.     (flet ((button (title callback)
  16.              (iup:button :title title
  17.                          :action callback
  18.                          :expand :horizontal)))
  19.       (let* ((dialog (iup:dialog
  20.                       (iup:vbox (list (button "File Dialog" 'file-dialog)
  21.                                       (button "Message Dialog" 'message-dialog)
  22.                                       (button "Color Dialog" 'color-dialog)
  23.                                       (button "Font Dialog" 'font-dialog)
  24.                                       (button "Scintilla Dialog" 'scintilla-dialog)
  25.                                       (button "Layout Dialog" 'layout-dialog)))
  26.                       :title "IUP Predefined Dialogs")))
  27.         (iup:show dialog)
  28.         (iup:main-loop)))))
  29.  
  30. (defun file-dialog (handle)
  31.   (let ((dialog (iup:file-dialog)))
  32.     (unwind-protect
  33.          (progn
  34.            (iup:popup dialog iup:+center+ iup:+center+)
  35.            (iup:message "File Dialog Example"
  36.                         (format nil "Selected ~A" (iup:attribute dialog :value))))
  37.       (iup:destroy dialog)))
  38.   iup:+default+)
  39.  
  40. (defun message-dialog (handle)
  41.   (let ((dialog (iup:message-dialog
  42.                  :dialogtype :warning
  43.                  :buttons :retrycancel)))
  44.     (unwind-protect
  45.          (progn
  46.            (setf (iup:attribute dialog :value) "Heap exhausted, game over.")
  47.            (iup:popup dialog iup:+center+ iup:+center+)
  48.            (iup:message "Message Dialog"
  49.                         (format nil "Got button response ~S"
  50.                                 (iup:attribute dialog :buttonresponse))))
  51.       (iup:destroy dialog)))
  52.   iup:+default+)
  53.  
  54. (defun color-dialog (handle)
  55.   (let ((dialog (iup:color-dialog
  56.                  :title "IUP Color Dialog"
  57.                  :showhex "YES"
  58.                  :showcolortable "YES"
  59.                  :showalpha "YES")))
  60.     (unwind-protect
  61.          (progn
  62.            (iup:popup dialog iup:+center+ iup:+center+)
  63.            (iup:message "Result"
  64.                         (format nil "Got button response ~S~%Got color ~A RGB (~A HSI, ~A)"
  65.                                 (iup:attribute dialog :status)
  66.                                 (iup:attribute dialog :value)
  67.                                 (iup:attribute dialog :valuehsi)
  68.                                 (iup:attribute dialog :valuehex))))))
  69.   iup:+default+)
  70.  
  71. (defun font-dialog (handle)
  72.   (let ((dialog (iup:font-dialog :title "IUP Font Dialog")))
  73.     (unwind-protect
  74.          (progn
  75.            (iup:popup dialog iup:+center+ iup:+center+)
  76.            (iup:message "Result"
  77.                         (format nil "Got button response ~S~%Got font ~S"
  78.                                 (iup:attribute dialog :status)
  79.                                 (iup:attribute dialog :value))))
  80.       (iup:destroy dialog)))
  81.   iup:+default+)
  82.  
  83. (defun scintilla-dialog (handle)
  84.   (let ((dialog (iup-scintilla:scintilla-dialog :title "IUP Scintilla Dialog")))
  85.     (unwind-protect
  86.          (iup:popup dialog iup:+center+ iup:+center+)
  87.       (iup:destroy dialog))))
  88.  
  89. (defun layout-dialog (handle)
  90.   (let ((dialog (iup:layout-dialog nil)))
  91.     (unwind-protect
  92.          (iup:popup dialog iup:+center+ iup:+center+)
  93.       (iup:destroy dialog)))
  94.   iup:+default+)
  95.  
  96.  
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104. #-sbcl (dialogs)
  105.  
  106. #+sbcl
  107. (sb-int:with-float-traps-masked
  108.     (:divide-by-zero :invalid)
  109.   (dialogs))
  110.  
Title: Re: Updating OxyScheme
Post by: Arnold on January 07, 2020, 02:16:46 AM
Hi Charles,

did you find out why "when" and "do" are seen as <closure> instead of <macro>? I tried to create o2scm.o2bas with int instead of quad, but also failed miserably. For the moment, I have given up.

In the past I was unable to attend the forum for a while. That is why I missed almost everything about 'Lisp in Basic'. I now understand that I have asked some superfluous questions that have already been answered. I also noticed that John also started a topic about Tinyscheme. He referred to the link in GitHub:

https://github.com/armornick/TinyScheme

This (adapted) contribution is interesting because the prepared CMakeList.txt can be used to create a tinyscheme dll for 32-bit and 64-bit. These were my steps to create the DLLs after unpacking:

create subfolders build32, build64
using msys mingw32 / mingw64, I applied these commands in the build directories:

cmake -G "MSYS Makefiles" ..
make

which will create the dll and a main app which calls the dll. These files can be compressed with the "strip" command.

Perhaps it is also possible to call the routines of the DLLs with O2. Then everything would be there to establish the collaboration between Oxygenbasic and Scheme, which would be my real goal. I think you mentioned something similar in Message 61.

Roland
 
Title: Re: Updating OxyScheme
Post by: Charles Pegge on January 09, 2020, 06:29:52 AM
Hi Roland, Mike,

I have not cracked it yet. It might be beneficial to do a complete recode from scratch, with unit tests, improved recursion depth, and other features to make it a more complete language. I think this would be a better investment of time if the intention is to do any significant programming with Scheme.

What do you think?

Title: Re: Updating OxyScheme
Post by: Arnold on January 09, 2020, 09:42:58 AM
I myself am impressed with how Mike managed to keep the spirit of Minischeme / Tinyscheme and to implement pointer structures. After a few experiments, I do not think there is a better way in Oxygenbasic, especially as far as applying macros like car(p), cdr(p) etc. are considered. But perhaps too many sys variables are used. Another problem for me is the multiple use of ivalue and the associated casts:  quad, double or integer index of a procedure. All of this worked for previous versions of Oxygen, but in the meantime O2 has changed a bit and some side effects will have been revealed somewhere.