Author Topic: QB64 does not interpret 0-place recursive function correctly  (Read 1780 times)

0 Members and 1 Guest are viewing this topic.

Offline qbguy

  • Newbie
  • Posts: 12
QB64 does not interpret 0-place recursive function correctly
« on: October 15, 2018, 10:26:36 PM »
Code: QB64: [Select]
  1. X = 5
  2.  
  3. IF X = 0 THEN F = 1 ELSE PRINT "*": X = X - 1: F = F
  4.  

Expected behavior: prints five stars, then 1.
Actual behaviour: prints a single star, then a 0.




Online bplus

  • Forum Resident
  • Posts: 5897
  • B+ Knot again!
Re: QB64 does not interpret 0-place recursive function correctly
« Reply #1 on: October 15, 2018, 10:41:51 PM »
Looks like F needs a dummy parameter:
Code: QB64: [Select]
  1. X = 5
  2. PRINT F(100)
  3.  
  4. FUNCTION F (t)
  5.     IF X = 0 THEN F = 1 ELSE PRINT "*";: X = X - 1: F = F(2)
  6.  
  7.  

Offline qbguy

  • Newbie
  • Posts: 12
Re: QB64 does not interpret 0-place recursive function correctly
« Reply #2 on: October 15, 2018, 10:48:54 PM »
I know you can just avoid 0-argument functions but the above code works in QBASIC.

Online bplus

  • Forum Resident
  • Posts: 5897
  • B+ Knot again!
Re: QB64 does not interpret 0-place recursive function correctly
« Reply #3 on: October 15, 2018, 11:11:58 PM »
Did QBASIC have the C++ middleman to feed? ;)

Offline Petr

  • Forum Resident
  • Posts: 1536
  • The best code is the DNA of the hops.
Re: QB64 does not interpret 0-place recursive function correctly
« Reply #4 on: October 16, 2018, 01:25:56 AM »
Code: QB64: [Select]
  1.  
  2. X = 5
  3. FOR result = 0 TO 5
  4.     IF F THEN PRINT F
  5.  
  6.  
  7.     IF X = 0 THEN F = 1 ELSE PRINT "*": X = X - 1
  8.  
  9.  

The original behavior of the program is logical. The result was requested only once and additionally the function f returns the number, and there was only one pass. Therefore f was correctly zero.
« Last Edit: October 16, 2018, 01:32:55 AM by Petr »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3185
    • Steve’s QB64 Archive Forum
Re: QB64 does not interpret 0-place recursive function correctly
« Reply #5 on: October 16, 2018, 10:32:53 AM »
It's a known bug that's been around forever, but it's one which doesn't seem to affect many people, so it's always been a low priority issue.  I don't think many people use functions recursively, so most never experience the issue. 

I've did a little digging into the problem before, and it seems as if it's a case of QB64 mistaking the name as a variable and not the function.  Under the hood, QB64 translates our code to C, then it compiles.  With the translation, variable names are changed slightly, so as to avoid confusion.

S = 2 may become SINGLE_S, or LONG_S, depending on the default variable type.  Functions are usually called FUNC_name (this is all if my memory isn't failing me again), and the issue is the line basically translates itself to:

FUNC_F = SINGLE_F - 1

When we use a parameter, QB64 correctly identifies the translation as a function, and all works as it should with FUNC_F = FUNC_F(dummyvalue) - 1...

***************

It sounds like a simple enough issue, but it's one that's hard to dig down and find inside QB64 itself.  To be honest, I'm not even 100% certain which part of QB64 does these exemptions/identifications for us...

Everyone needs to remember: Galleon was the one who originally wrote QB64, and all the rest of us are just trying to sort through someone else's long -- undocumented -- spaghetti code, and sometimes, some issues are difficult to track and correct, like this one.  :)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3185
    • Steve’s QB64 Archive Forum
Re: QB64 does not interpret 0-place recursive function correctly
« Reply #6 on: October 16, 2018, 01:10:32 PM »
Taking time to look at the output of the c-file for the original post problem, here's what we end up seeing:

*__SINGLE_X=*__SINGLE_X- 1 ;
*_FUNC_F_SINGLE_F=*_FUNC_F_SINGLE_F;

_FUNC_F_SINGLE_F is how QB64 stores the value of F while inside the function F, before it returns it to us.  What the line in question should read is:

*_FUNC_F_SINGLE_F=FUNC_F();

Make that change, run recompile_win.bat from inside the temp folder, and PRESTO -- output as expected...

The only issue is:

Does anyone know where inside QB64 to change our interpreter, so that it'll output that proper line for us??

Unfortunately, I haven't found it and sorted it out yet.  :(

The change seems simple enough, but where to make that change has me scratching my head ATM.  :P
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline TerryRitchie

  • Forum Resident
  • Posts: 611
  • Semper Fidelis
Re: QB64 does not interpret 0-place recursive function correctly
« Reply #7 on: October 16, 2018, 01:12:56 PM »
Everyone needs to remember: Galleon was the one who originally wrote QB64, and all the rest of us are just trying to sort through someone else's long -- undocumented -- spaghetti code, and sometimes, some issues are difficult to track and correct, like this one.  :)

I can attest to that statement. One of the things that originally drew me to QB64 was the freely available source code ... until I had a look at it.  Spaghetti is an understatement. I was so disappointed to see the source code in the state it was in. I marvel at how others have taken the time to sort through and modify it for our benefit. They deserve a HUGE THANK YOU!
In order to understand recursion, one must first understand recursion.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3185
    • Steve’s QB64 Archive Forum
Re: QB64 does not interpret 0-place recursive function correctly
« Reply #8 on: October 22, 2018, 03:44:44 PM »
Heres a fix for this (though it's kinda a hack):

Open QB64.bas.
Scroll all the way to the end of FUNCTION setrefer.
Between the line where we build l$ and the next line where we print it to file, insert this:


        l$ = r$ + "=" + e$ + ";"
Code: QB64: [Select]
  1.         IF LEFT$(r$, 7) = "*_FUNC_" THEN 'if the left side is a FUNCTION = statement, we don't want its equivelant on the right side.  We want a function call instead.
  2.             'This cures the issue below, which destroys recursive functions:
  3.             'FUNCTION f
  4.             'f = f
  5.             'END FUNCTION
  6.             DO
  7.                 i = INSTR(e$, r$)
  8.                 IF i THEN
  9.                     l1$ = LEFT$(r$, i + 1)
  10.                     i2 = INSTR(8, r$, "_")
  11.                     m1$ = MID$(r$, 3, i2 - 3) + "()"
  12.                     e$ = LEFT$(e$, i - 1) + m1$ + MID$(e$, i + LEN(r$))
  13.                 END IF
  14.             LOOP UNTIL i = 0
  15.             l$ = r$ + "=" + e$ + ";"
  16.         END IF
        PRINT #12, l$


***************************
Sorting out the evaltype routine is beyond me, but here's the logic behind this simple fix:
If the translation on the left is a "FUNCTION_Variable = something" then we should never see that same variable on the right side of the equal sign.  Instead, we should see a call back to the function.

The above checks the output, looks for the glitch, and makes the substitution for us.

It's kinda a hack, but it works -- unless somebody has a more elegant solution?
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!