|
Post by clamzonprozac on Jun 9, 2024 6:08:34 GMT 1
Howdy! Admittedly the BaCon docs instruct one to use string variables as input to VAL(). Noting the use of VAL(MID$(...)) in BaCon itself I decided to try passing a function return string to VAL myself. The result? No compile time error message, and some side effect twiddling of a global variable (j ?) when executed. With this test code the issue is nicely reproducible...
REM ---- test code : val.bac -------------------------------------------------------- GLOBAL test_table$ = "|60,41,12,345,67,89|fingertip,bismark|hh,77|" GLOBAL i,j,n,test_table_len TYPE int GLOBAL sg$ test_table_len = LEN(test_table$)
FUNCTION get_test$() TYPE STRING LOCAL c$,s$ s$ = "" REPEAT c$ = MID$(test_table$,i,1) s$ = s$ + c$ INCR i UNTIL (c$ = ",") OR (c$ = "|") OR (i >= test_table_len +1) s$ = MID$(s$,1,LEN(s$)-1) : ' strip trailing delimiter PRINT "get_test$ RETURNING[",s$,"]" RETURN s$ END FUNCTION
PRINT "NORMAL OUTPUT (a string supplies input to VAL)"
i = 2 j = 1 WHILE j <= 6 sg$ = get_test$() n = VAL(sg$) PRINT " VAL converts to ", n INCR j WEND PRINT "NOW TO SHOW THE PROBLEMATIC OUTPUT created by" PRINT "supplying VAL() with input from a string function..." i = 2 j = 1 WHILE j <= 6 n = VAL(get_test$()) PRINT " VAL converts to ", n INCR j WEND
REM -------------------------------------------------------------------------------------------------
I get the feeling that a fix here might enhance the capabilities of other BaCon keywords.
Ahhh... Saturday night fun in the Man Cave (aka Lab)!
Kind Regards to All, -Roger
|
|
|
Post by Pjot on Jun 9, 2024 8:02:10 GMT 1
Hi Roger, Your issue occurs because of a mix of global and local variables in one function. The variable 'i' is increased globally, while the function 'get_test$()' returns a local result. Usually, programmers would provide the data as arguments instead, e.g. 'get_test$(test_table$, i)' and invoke it from the main scope. In such situation, the problem would not have occurred. Even though your program might not demonstrate the "recommended" programming practice, it should work, as it is syntactically correct. So what went wrong? It demonstrates an unwanted side-effect from an argument check for VAL. In the C code, the VAL function is generated as: #define VAL(x) ((x) != NULL ? atof(x) : 0)
This means that the argument first is verified whether or not it is a NULL pointer. The check is required, because in case of a NULL pointer, the result is a crash. So when providing the 'get_test$()' function as an argument, it needs to be executed to see the result. The variable 'i' is increased there. Then, the 'atof' function from C is used to actually convert the non-NULL to a double value. The variable 'i' is increased once again. The fix for the C code is not to define VAL as an inline if, but as an external function altogether. This allows any argument to be evaluated in the function header and the check can be performed in the external function. The latest code to fix this issue can be found here. HTH Peter
|
|
|
Post by clamzonprozac on Jun 9, 2024 10:55:17 GMT 1
Thank you, Peter. It works as expected now!
The functioning of VAL as an inline seems like an obscure C-style "sleight of hand" trick. I'd never considered it would work that way. Too much to learn, too much to forget.
|
|
|
Post by clamzonprozac on Aug 3, 2024 2:07:31 GMT 1
Hi Peter, I was mucking about with another function using VAL() and it didn't want to convert a string to the expected int contained within it. I went back to code discussed and fixed several weeks ago and that doesn't work as it used to (the original working example now doesn't work (zero is returned) but the fixed example still works). Both examples in the code used to work after the fix. Is it my imagination or did something break lately? GLOBAL test_table$ = "|60,41,12,345,67,89|fingertip,bismark|hh,77|" GLOBAL i,j,n,test_table_len TYPE int GLOBAL sg$ test_table_len = LEN(test_table$)
FUNCTION get_test$() TYPE STRING LOCAL c$,s$ s$ = "" REPEAT c$ = MID$(test_table$,i,1) s$ = s$ + c$ INCR i UNTIL (c$ = ",") OR (c$ = "|") OR (i >= test_table_len +1) s$ = MID$(s$,1,LEN(s$)-1) : ' strip trailing delimiter PRINT "get_test$ RETURNING[",s$,"]" RETURN s$ END FUNCTION
PRINT "NORMAL OUTPUT (a string supplies input to VAL)"
i = 2 j = 1 WHILE j <= 6 sg$ = get_test$() n = VAL(sg$) PRINT " VAL converts to ", INCR j WEND PRINT "NOW TO SHOW THE PROBLEMATIC OUTPUT created by" PRINT "supplying VAL() with input from a string function..." i = 2 j = 1 WHILE j <= 6 n = VAL(get_test$()) PRINT " VAL converts to ", n INCR j WEND
Kind Regards, -Roger
|
|
|
Post by Pjot on Aug 3, 2024 7:03:03 GMT 1
Hi Roger,
Your program works as designed, but your program should actually PRINT the variable 'n' at line 26.
BR Peter
1 GLOBAL test_table$ = "|60,41,12,345,67,89|fingertip,bismark|hh,77|" 2 GLOBAL i,j,n,test_table_len TYPE int 3 GLOBAL sg$ 4 test_table_len = LEN(test_table$) 5 6 FUNCTION get_test$() TYPE STRING 7 LOCAL c$,s$ 8 s$ = "" 9 REPEAT 10 c$ = MID$(test_table$,i,1) 11 s$ = s$ + c$ 12 INCR i 13 UNTIL (c$ = ",") OR (c$ = "|") OR (i >= test_table_len +1) 14 s$ = MID$(s$,1,LEN(s$)-1) : ' strip trailing delimiter 15 PRINT "get_test$ RETURNING[",s$,"]" 16 RETURN s$ 17 END FUNCTION 18 19 PRINT "NORMAL OUTPUT (a string supplies input to VAL)" 20 21 i = 2 22 j = 1 23 WHILE j <= 6 24 sg$ = get_test$() 25 n = VAL(sg$) 26 PRINT " VAL converts to ", :'<-----------where is n? 27 INCR j 28 WEND 29 30 PRINT "NOW TO SHOW THE PROBLEMATIC OUTPUT created by" 31 PRINT "supplying VAL() with input from a string function..." 32 33 i = 2 34 j = 1 35 WHILE j <= 6 36 n = VAL(get_test$()) 37 PRINT " VAL converts to ", n 38 INCR j 39 WEND
|
|
|
Post by clamzonprozac on Aug 3, 2024 10:04:24 GMT 1
How embarrassing. Sorry. Talk about looking but not seeing! Thank you, Peter... 'n' was there the last time I worked with that demo (he says while banging his head on the desk).
|
|
|
Post by clamzonprozac on Aug 3, 2024 10:31:51 GMT 1
But... wait... (as if self face saving excuses happen to grow on trees) shouldn't PRINT throw a compile time error if there's a comma at the end of the print list? I know a semicolon has the power to suppress a new line but a dangling comma? As some may say around here: " well, that just ain't right". While we're on the topic: Last week I discovered (by happy accident) that a comma can be used to do the same as a semicolon or an AND as a separator token between arguments for BETWEEN. Kind Regards, -Roger
|
|
|
Post by Pjot on Aug 3, 2024 13:50:57 GMT 1
Well, fair enough. The error handling in BaCon can be improved anyway, also for other statements. The latest beta now has this check. Hope your desk survived BR Peter
|
|
|
Post by clamzonprozac on Aug 5, 2024 22:26:08 GMT 1
Hi Peter, Before I forget: the desk wants me to let you know how much it appreciates your concern for its health ... a compression bandage, some furniture oil, a couple of bottles of aspirin, a little bed rest ... its told me it will soon be as good as new. Anyway, last night I was attempting to brew up some self-modifying source code (yet another sub-project) and ran into an issue with OPEN xxx FOR APPENDING, which in turn ballooned into a hunch that lead to my testing for related operand errors. Read my comments, compile the code, you'll understand ( ) ... Oh, to be clear from my last post as to the undocumented comma token appearing to be allowed between the operands of BETWEEN: it was for information only. I, for one, rather prefer the comma. That should be all for today... Kind Regards, -Roger
|
|
|
Post by Pjot on Aug 6, 2024 5:29:46 GMT 1
Hi Roger, Again, thanks for your patience. As mentioned, the syntax checking in BaCon can use some improvements, even though there are more than 175 spots where BaCon checks syntax already. Your example is a clear illustration. Ultimately, this is due to the way BaCon itself was implemented. It started as a simple Kornshell script and grew bigger. So right from the start, BaCon has no clearly defined context-free grammar which is used in an Abstract Syntax Tree. Therefore, each statement or function is being checked on an individual basis. Fortunately, improving syntax checking is fairly easy to do. The latest beta now has this check for the OPEN statement. Regarding the BETWEEN/BEYOND keywords, BaCon makes use of an internal "mini-parser", which will return chunks of text separated either by comma or semicolon. Therefore, it is an unintended side effect that BETWEEN/BEYOND also accept a comma, but it's no problem either, as far as I am concerned. If you write code which is syntactically wrong, you'll probably run into more situations like this. Nobody protects us from typos or wrong memorization. Even I myself make (syntax) mistakes when using BaCon.
So do not hesitate to proceed and let me know other (syntax) problems. I'll be happy to add improvements where necessary. Thanks again, Best regards Peter
|
|