Using GCB Great Cow BASIC (0.98.01 2017-10-27) on Linux Mint 18.3
There appear to be a considerable range of numeric values of FOR/NEXT loop parameters that produce unexpected operations but none get a mention in the documentation. A specific example is
For i = 1 to 252 step 5
This initially produces the expected steps of i=1,6,11,16... etc, but then spans the entire range again
with i= 0,5,10,15 etc.
For i = 252 to 1 step 5
This loop spans the entire range 4 times.
The unexpected overflow problems can be dispelled if the loop termination test is restructured to not perform any operations on the loop counter outside the expected range of the loop. A test like this
'For incrementating loops
If end_value-loop_value >= step_value then
add step_value to loop_value and branch back to loop start
'For decrementating loops
If loop_value-end_value >= step_value then
subtract step_value from loop_value and branch back to loop start
For completely different reasons this loop is never executed but there is no mention in the documentation of the limitation.
bot = 1
top = 252
For i = top to bot step 5
It appears that there is no runtime support for decrementing loops so this bit of assembler ignores the code.
I have checked the source code for the FOR loop and and this documentation was helpfully provided...
'Then to this: (27/8/2010)
'V = SV - ST
'If SV not const or EV not const, if V > EV then goto SysForLoopEnd(n)
'SysForLoop(n):
'V += ST
'...
'if V <= EV then goto SysForLoop(n)
'SysForLoopEnd(n):
This is JUNK. It only works as expected, that is the value of V (loop variable) is on or between the limits (SV - start value, EV - end value) for the special case where the difference between the limits (EV-SV) is an integral multiple of the step size (ST). For all other cases the final pass will have a value of V higher than EV. This is not what a programmer would expect because no other language would dream of doing so.
In case the big numbers in my first example reduced appreciation of the issue, here are some little ones.
bot = 1
top = 4
Do forever
LCDcmd(line1) : Print "Test increment"
for ipwr = bot to top step 2
LCDcmd(line2) : Print ipwr : LCDspace 2
wait 1 s
next
loop
On the first pass ipwr = 1, this is easy.
On the second pass ipwr = 3, this is reassuring.
On the third unexpected pass ipwr = 5, this is wrong.
Don't try and tell a programmer they should have used some other number, there are many valid applications where the loop parameters are derived from independent data or measurements and the programmer has little control over what is used. They just expect a defined result for any set of legal numbers.
To be really helpful have a defined result for the special case of step=0, presently it produces an infinite loop. This is theoretically correct but disruptive in real life, a more practical result would be a single pass with V = SV.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
@Tony Bolton, this is an interesting issue. I have not yet bumped into it, but it seems it could happen.
'Then to this: (27/8/2010)
'V = SV - ST
'If SV not const or EV not const, if V > EV then goto SysForLoopEnd(n)
'SysForLoop(n):
'V += ST
'...
'if V <= EV then goto SysForLoop(n)
'SysForLoopEnd(n):
This is JUNK.
Is there a better way to do this that would produce the results you are expecting? What would you suggest to make this work as anticipated?
Last edit: Moto Geek 2018-01-31
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The issue is not as simple as it looks, as you say. The loop termination will required to handle the overflow and the underflow conditions that may happen. Also, the compiler does assume certain conditions which I can document when I get a moment.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
When using FOR-NEXT with Great Cow BASIC you may need to handle an overflow situation.
An overflow will happen when the next step in your increment exceeds the variable type.
Consider. For = 250 to 255 STEP 3. The steps will be 250, 253 and 0 etc.
As the third in this sequence has overflowed to 0 not 256 the For-Next loop will continue and you may have unexpected outcomes from your program.
To resolve this. Do not use a FOR-NEXT but a construct that will ensure an overflow is controlled.
The following code shows how to use a DO-LOOP to increment (the constant __INC) from the base ( __MIN) to a maximum value ( __MAX).
This program tests for an overflow condition and will exit, and, the program tests to ensure the next value is less than the maximum.
Consider. __MIN = 250, __MAX = 255 and IINC=3.
The steps will be 250 and 253. There is no overflow and the incremented value is always less then the maximum
#chiplgt8fx328p
#optionExplicit'USART settings for USART1
#defineUSART_BAUD_RATE9600
#defineUSART_TX_BLOCKING
#defineUSART_DELAYOFF'Wait for terminal to select.. or, give time for me to get to terminal....wait2s'******************************************** START OF CODE ***********************
#DEFINE__MIN250
#DEFINE__MAX255
#DEFINE__INC3'This variable needs to be of the correct type Byte, Word etc to handle the maximum valuedim__nextremetestasbyte__nextremetest=__MINdo'Code to show results. Remove from target codehserprint__nextremetestHSerPrintCRLFwait100ms'Do Stuff'...'Do Stuff__nextremetest=__nextremetest+__INC'Test of overflowifcthenexitdo'Now test for maximum has not been exceededif__nextremetest>__MAXthenexitdoloop
This code is efficient in terms coding.
And, this method should be used there is a risk that an overflow situation may happen.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have updated the compiler and I have rewritten the FOR-NEXT handler.
I have used the insights provided by Tony and with some adaption I have rewritten. The new handler will now support more options and is intended to be reliable.
I have tested many use case as follows, but, I need YOU to test.
From
To
Step
Comments
Constant_Low
Constant__Hi
Not present
Assumes step 1 - counts up
Constant_Hi
Constant__Lo
Not present
counts up i.e. 240 to 8 passing through 0
Constant_Low
Constant__Hi
Step Constant = 1
counts up
Constant_Hi
Constant__Lo
Step Constant = 1
counts up i.e. 240 to 8 passing through 0
Constant
Constant
Step Constant = 0
loops. never exits
Variable
Variable
Not Present
Assumes step 1 - counts up
Variable
Variable
Positive Integer
counts step up - handling overflows
Variable
Variable
Negative Integer
counts step down- handling overflows
Variable
Variable
Step Integer=0
Loops, until Step is specified
Variable
Variable
Positive Constant
creates system integer and counts step up - handling overflows
Variable
Variable
Negative Constant
creates system integer and counts step down - handling overflows
If this is not tested. I just wasted a weeks work... so, please let me know when you can find some time to look at this huge change,
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
To test. Install RC42 and then I will upload the new test compiler and the language file. I have a series of test programs - these may help but I think it is best to create test scenarios that you typically use.
Sign up, Sign up, Sign up.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The following test program now works as expected. This is totally based on Tony's post. I changed to serial to automate the testing.
Evan
#defineNewNextForhandler#chip16f88#optionExplicit'USART settings for USART1 #define USART_BAUD_RATE 9600 #define USART_TX_BLOCKING #define USART_DELAY OFF dim ipwr, bot, top as Byte bot = 1 top = 252 HSerPrint "Test increment" HSerPrintCRLF'Thislooprunstherangetwiceinoriginalcodeforipwr=bottotopstep5HSerPrintipwrHSerPrint", "wait10msnextwait1sHSerPrintCRLFHserPrint"Test decrement"HSerPrintCRLF' This loop runs 4 times in original code for ipwr = 252 to 1 step 5 HSerPrint ipwr HSerPrint ", " wait 10 ms next wait 1 s HSerPrintCRLF 2 HSerPrint "Test runtime" HSerPrintCRLF 'Thisneverrunsinoriginalcodeforipwr=toptobotstep5HSerPrintipwrHSerPrint", "wait10msnextwait1s
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Please test. You must use RC42 as the baseline and then apply the EXE and MSG files to your GreatCowBASIC folder. This will update to the new FOR-NEXT handler.
To enable/test the new handler you must add #define NewNextForhandler to your program. This will then ensure you can test the new handler, and, you can comment out to test/compare against the old handler.
The patch zip is here. The zip contains many of the programs used to test. Please add to this collection.
This is the code that being used as the basis. The compiler is simply doing this. So, the 'proof code' program in the zip let us see what is happening without using the new handler.
#chip16f88#optionExplicit'USART settings for USART1 #define USART_BAUD_RATE 9600 #define USART_TX_BLOCKING #define USART_DELAY OFF dim LoopVar, StartValue, EndValue, ccount as Integer dim StepValue as Integer //Set the value here. StartValue = -12 EndValue = -14 StepValue = -2 If StepValue.15 = 0 then //handle a positive step value 'StartingcodeLoopVar=StartValueposloop:'do stuff - your code HSerPrint LoopVar HSerPrintCRLF if EndValue-LoopVar >= StepValue then LoopVar = LoopVar + StepValue goto posloop end if else //handle a negative step value 'StartingcodeLoopVar=StartValuenegloop:'do stuff - your code HSerPrint LoopVar HSerPrintCRLF 'whilethe*-1looksodd,itisnot.ThiscatersfornegativestepsandthenpermitsaSimpleadditiononthenextloifLoopVar-EndValue>=(StepValue*-1)thenLoopVar=LoopVar+StepValuegotonegloopendifendif
You will see more warnings when using the new handler, and, you will be shown how to mask these warnings. These warnings are intended to inform users when specific constraints may influence the operation of the new handler. You can 1) Improve the warnings by editing the MSG file 2) Ask for more warnings to be added to the final complier 3) Recommend we remove warnings via this thread. :-)
Have fun.... post results.
Last edit: Anobium 2021-03-17
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
There will be issues that need to be sorted but they are minor. Take the following example from the SPIRAM program. Where the EndValue is 0x1F (d31)-2, so, this is an end value of 29. Old code the the last LoopValue to 30 and the new code set the last LoopValue to 28. Clearly, the new code is correct but this will mean the user code should be revised.
New compiler exe uploaded. Dated 17/3/2021 Use ForNextPatch002.zip
Add new modifier to the FOR-NEXT. #IGNOREWARNING
#IGNOREWARNING will override the warnings for an explicit instance of FOR-NEXT. This should be used in libraries to ensure the user program controls the warnings.
I didn't want to upset anyone with my comments.
It's true that I have never had a problem with for next step.
If the for next range is not exactly divisible by the step value then it will not reach the end value.
This seems a user problem not a compiler problem. Sorry if sloppy programming upset anyone.
I realise and appreciate the work the gcb team has done, even if it's for something I don't use.
I wonder if the overflows in the glcd lib still exist. There are so many displays supported now.
Say you draw a square. erase it and redraw it 1 pixel down and repeat in a constant loop you will find different results on different displays.
Some times the square will slowly go off the bottom of the screen then after a while will reappear at the top and do the same thing again.
A different display would behave differently but the point is there's no checking for plot-draw that's greater than the screen resolution. Last time I looked it seemed it was checking but there's lots of code in glcd to examine. An excellent bit of coding with universal commands.
I really got to get my head together to do animated graphics and a test of lots of gcb commands.
I guess I've been lucky so far. I did report the box fill overflow which was sorted so I'm not a time waster.
I wanted to do an "Asteroids" game but modifying the draw function to check each segment being off screen would be too slow.
Last edit: stan cartwright 2021-07-27
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Using GCB Great Cow BASIC (0.98.01 2017-10-27) on Linux Mint 18.3
There appear to be a considerable range of numeric values of FOR/NEXT loop parameters that produce unexpected operations but none get a mention in the documentation. A specific example is
This initially produces the expected steps of i=1,6,11,16... etc, but then spans the entire range again
with i= 0,5,10,15 etc.
This loop spans the entire range 4 times.
The unexpected overflow problems can be dispelled if the loop termination test is restructured to not perform any operations on the loop counter outside the expected range of the loop. A test like this
For completely different reasons this loop is never executed but there is no mention in the documentation of the limitation.
It appears that there is no runtime support for decrementing loops so this bit of assembler ignores the code.
This is a sample program showing the effects.
Not undocumented but a consquence of the nature of the commands.
For i = 1 to 252 step 5 .. 1, 6, 11 .. 246, 251, 1(or 256 if word). Therefore the range needs to be addressed, or your loop needs to mange the overun.
Simply use 1 to 251.
I have checked the source code for the FOR loop and and this documentation was helpfully provided...
This is JUNK. It only works as expected, that is the value of V (loop variable) is on or between the limits (SV - start value, EV - end value) for the special case where the difference between the limits (EV-SV) is an integral multiple of the step size (ST). For all other cases the final pass will have a value of V higher than EV. This is not what a programmer would expect because no other language would dream of doing so.
In case the big numbers in my first example reduced appreciation of the issue, here are some little ones.
On the first pass ipwr = 1, this is easy.
On the second pass ipwr = 3, this is reassuring.
On the third unexpected pass ipwr = 5, this is wrong.
Don't try and tell a programmer they should have used some other number, there are many valid applications where the loop parameters are derived from independent data or measurements and the programmer has little control over what is used. They just expect a defined result for any set of legal numbers.
To be really helpful have a defined result for the special case of step=0, presently it produces an infinite loop. This is theoretically correct but disruptive in real life, a more practical result would be a single pass with V = SV.
Point taken - I will update the help to clarify this constraint.
@Tony Bolton, this is an interesting issue. I have not yet bumped into it, but it seems it could happen.
This is JUNK.
Is there a better way to do this that would produce the results you are expecting? What would you suggest to make this work as anticipated?
Last edit: Moto Geek 2018-01-31
I suggest the folowing steps...
(1) Start with the loop termination algorithm I outlined in the frst post of this thread.
(2) Try to add step=0 handling, should be reasonably easy.
(3) Try to add runtime step decrement handling, this will have a more difficult effort/size/complexity compromise.
(4) Conduct a rigorous gamut of testing, especially considering the extremes of the range of each variable type to identify over/under flows.
I have added this to the list to investigate.
The issue is not as simple as it looks, as you say. The loop termination will required to handle the overflow and the underflow conditions that may happen. Also, the compiler does assume certain conditions which I can document when I get a moment.
Just added to the Help in the FOR-NEXT section.
Handling a FOR-NEXT Overflow
When using FOR-NEXT with Great Cow BASIC you may need to handle an overflow situation.
An overflow will happen when the next step in your increment exceeds the variable type.
Consider. For = 250 to 255 STEP 3. The steps will be 250, 253 and 0 etc.
As the third in this sequence has overflowed to 0 not 256 the For-Next loop will continue and you may have unexpected outcomes from your program.
To resolve this. Do not use a FOR-NEXT but a construct that will ensure an overflow is controlled.
The following code shows how to use a DO-LOOP to increment (the constant __INC) from the base ( __MIN) to a maximum value ( __MAX).
This program tests for an overflow condition and will exit, and, the program tests to ensure the next value is less than the maximum.
Consider. __MIN = 250, __MAX = 255 and IINC=3.
The steps will be 250 and 253. There is no overflow and the incremented value is always less then the maximum
This code is efficient in terms coding.
And, this method should be used there is a risk that an overflow situation may happen.
" if c then exit do"
What is c ????????
C is the Carry Flag. Do not use status.C register as using C is managed by the compiler and works across all chip families.
So, testing C when certain operations are happening is useful.
There are many functions that use C. See http://gcbasic.sourceforge.net/help/_rotate.html you will see another use of C
THANKS !
Testers Needed.
I have updated the compiler and I have rewritten the FOR-NEXT handler.
I have used the insights provided by Tony and with some adaption I have rewritten. The new handler will now support more options and is intended to be reliable.
I have tested many use case as follows, but, I need YOU to test.
If this is not tested. I just wasted a weeks work... so, please let me know when you can find some time to look at this huge change,
Sign up, Sign up, Sign up.
To test. Install RC42 and then I will upload the new test compiler and the language file. I have a series of test programs - these may help but I think it is best to create test scenarios that you typically use.
Sign up, Sign up, Sign up.
The following test program now works as expected. This is totally based on Tony's post. I changed to serial to automate the testing.
Evan
Sign me up, I will some testing on arduino nano.
Domenic - thank you. I will post instructions soon.
Testers
Please test. You must use RC42 as the baseline and then apply the EXE and MSG files to your GreatCowBASIC folder. This will update to the new FOR-NEXT handler.
To enable/test the new handler you must add
#define NewNextForhandler
to your program. This will then ensure you can test the new handler, and, you can comment out to test/compare against the old handler.The patch zip is here. The zip contains many of the programs used to test. Please add to this collection.
This is the code that being used as the basis. The compiler is simply doing this. So, the 'proof code' program in the zip let us see what is happening without using the new handler.
You will see more warnings when using the new handler, and, you will be shown how to mask these warnings. These warnings are intended to inform users when specific constraints may influence the operation of the new handler. You can 1) Improve the warnings by editing the MSG file 2) Ask for more warnings to be added to the final complier 3) Recommend we remove warnings via this thread. :-)
Have fun.... post results.
Last edit: Anobium 2021-03-17
I have ran the static tests on all the demos.
There will be issues that need to be sorted but they are minor. Take the following example from the SPIRAM program. Where the EndValue is 0x1F (d31)-2, so, this is an end value of 29. Old code the the last LoopValue to 30 and the new code set the last LoopValue to 28. Clearly, the new code is correct but this will mean the user code should be revised.
There may be many cases where this happens.
OLD 0,2,4.. 26,28,30
New 0,2,4.. 26,28
New compiler exe uploaded. Dated 17/3/2021 Use ForNextPatch002.zip
Add new modifier to the FOR-NEXT. #IGNOREWARNING
#IGNOREWARNING
will override the warnings for an explicit instance of FOR-NEXT. This should be used in libraries to ensure the user program controls the warnings.Example shown below from epd_epd2in13d.h library
The user will get warnings but the library is assumed to be tested!
Last edit: Anobium 2021-03-17
I didn't want to upset anyone with my comments.
It's true that I have never had a problem with for next step.
If the for next range is not exactly divisible by the step value then it will not reach the end value.
This seems a user problem not a compiler problem. Sorry if sloppy programming upset anyone.
I realise and appreciate the work the gcb team has done, even if it's for something I don't use.
I wonder if the overflows in the glcd lib still exist. There are so many displays supported now.
Say you draw a square. erase it and redraw it 1 pixel down and repeat in a constant loop you will find different results on different displays.
Some times the square will slowly go off the bottom of the screen then after a while will reappear at the top and do the same thing again.
A different display would behave differently but the point is there's no checking for plot-draw that's greater than the screen resolution. Last time I looked it seemed it was checking but there's lots of code in glcd to examine. An excellent bit of coding with universal commands.
I really got to get my head together to do animated graphics and a test of lots of gcb commands.
I guess I've been lucky so far. I did report the box fill overflow which was sorted so I'm not a time waster.
I wanted to do an "Asteroids" game but modifying the draw function to check each segment being off screen would be too slow.
Last edit: stan cartwright 2021-07-27
I give up.
This discussion closed in March 2021
I can revert all the changes back in about 2 seconds. It will revert back to the broken FOR-NEXT loop.
Get involved to test and resolve the issue, or, I will revert.