I've written a large program for the 16F1829. As it reached the point where it filled 98% of the device (with much work left to do) I switched to the larger and faster 18F15Q40.
The program has been progressing until this afternoon when I added more features, the program was occupying 48% or so of the memory before I sat down after lunch. Having added some extra features, I attempted to compile and was surprised to see that many lines of the program showed errors:
With the error(s) stating that the two lines 1818 and 1823, Events(1) being undeclared. There were other errors found, all in the same subroutine, all relating to variables being undeclared.
I was very surprised as I had been using near identical code earlier in the day with zero problems.
Looking at the produced .asm file shows that the references to Events(1) on lines 1818 and 1823 have not been substituted with their "system" variable names, but are referenced to as Events(1). The line 1827 "Let Events(1) = H1Events1 + H2Events1" is compiled correctly, and shows that Events(1) has been assigned the "system" variable name of "SYSEVENTS_1".
Many, many, many thanks for that. It now, indeed, compiles.
Really odd that I have been using "Events()" on the 18F15Q40 for well over a week (and on the 16F1829 on and off for 2 years or so) with no problems whatsoever. Program compiled and ran on the 18F15Q40 perfectly well up until this afternoon, the earlier version without the mods I made is still running now at work and it uses "Events()" in vast numbers of subroutines. I did a search and replace of "Events(" in the code, it found 66 statements referring to "Events(" all working normally. How very odd.
It is an ambitious, untidy and rather unweildy set of code. I'm far from certain I will actually be able to to get it to work fully. It is for (yet) another Change Machine. In my opinion I've previously built and coded a much, much better design in every way. This is for a replacement PCB (and code) for one of our competitor's machines where their electronic design is electrically unreliable. I'm confident mine will be electrically reliable but not in the least confident I can get the complex software to be reliable. Still, it is a quiet period at work now so I've got time to sit and code 'till my head bursts - which it did today.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have spent all day trying to find the root cause to the issue.
An update.
Symptom
Error message the an array or array element is not defined.
Error: Variable EVENTS(1) was not explicitly declared.
Examination
The error message states a variable is not defined (not array element) and ASM shows variable usage for a byte variable. However, this is actually defined as an array element in the source program.
H2Events1 = Events(1)
movff EVENTS(1),H1EVENTS1
The ASM also show the allocation of a byte memory address for a variable called EVENT(1)
The use of EVENT(1) is a symptom that the program is meant to access an element with the array EVENT() but is it actually accessing a byte variable that has no relation to the array. :-(
The user code is impacting the compilation process. The failure is a critical failure that should not occur.
The specific user case follows:
H2Events1 = Events(1) where the source array name is substring of the target variable AND the array element is a CONSTANT. In this case INSTR("H2EVENT1", "EVENT") <> 0 so, EVENT is within H2EVENT1.
Ensure the source array name is not a substring of the target variable.
Root Cause
The root cause is deep inside the compiler within a function that examines if a string exists with another string. This is a complex comparison that needs to address maths functions, where a simple INSTR() will not cover the range of use cases.
This specific use case of where the source array name is substring of the target variable ( the error case) does not return the correct value.
WholeINSTR() why it does not match the substring to 2 hence the failure to indentiify the EVENT(n) as an array element.
The root cause is the function WholeINSTR() . There is no documentation in WholeINSTR() and it may take a many more hours to understand how this function operates to ensure any change does not break other users of WholeINSTR(). WholeINSTR() is used many times across the compiler, so, great care must be taken.
End of report. I will try to fix asap.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
All other references to "Events(1)" assigned the result or value to a variable which didn't incorporate the word 'Events" anywhere within the target variable name.
I was trying to assign the variables returned in Events() to a new variable as I knew I would need to update Events() in the following lines of code and wanted to preserve them before they were overwritten. I named them "H1Events1" and H2Events1" (and H1Events2, H2Events2 and so on) so I could more easily recognise the values held by them. Earlier iterations of the code didn't need to reuse "Events()" and so didn't need to save the values in additional variables.
I should add that the suggestion of changing "Events()" to "Event_s()" did work correctly. I've made some major changes to the code and it now is working as I wanted. Been on it all day (again) and the Change Machine is now able to pay the value of inserted coin distributed evenly across two hoppers, halving the time taken to dispense the coins, with any payment errors detected and then corrected where required.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Trying to fix this for the future is proving to be very hard. I need more eyes on this issue.
I have expanded the function that test for a substring within a string, adding a load of debug, as this has ‘magic’ that is hard to understand what is actually going on.
And, I have added ( between the change number #1199 ) a new test for that is meant to resolve H1Events1 = Events (1) or H1Events1 = Events(1) where the array string search would be Events.
Findings/Assumption today.
None of the original tests give a score where T > 0
So, is it safe to assume the string exists twice as the 'No match at all - exit with 0 test have been passed – We have at least one match but failed all tests.
So, replace with the FS (#0030) char, and, do it all again.
For this specific use case if becomes H1?FS?1 = Events (1) or H1?FS?1 = Events(1), so, original now work.
Your thoughts please?
Evan
FUNCTIONWholeINSTR(DataInAsString,FindInAsString,SearchAgainAsInteger=-1)AsIntegerDimAsStringDataSource,Temp,FindDimAsIntegerTDataSource=UCase(DataIn):Find=UCase(FindIn)ifWholeINSTRdebugthenprint"$"+DataSource+"$","|"+Find+"|"," results ",IFINSTR(DataSource,Find)=0THEN'No match at all - exit with 0 WholeINSTR = 0 if WholeINSTRdebug then print 0 EXIT FUNCTION End If IF LEN(DataSource) = LEN(Find) THEN 'Perfectmatch-exitwith2WholeINSTR=2ifWholeINSTRdebugthenprint2EXITFUNCTIONEndIfDoWholeINSTRAgain:T=0IFINSTR(DataSource,Find)=1THEN'MATCHED at the start of the line, so set T to 1 ( not sure why yet... ) if WholeINSTRdebug then print "a"; T = 1 End if IF T = 0 THEN 'OnlygetherewhenthesubstringisNOTatthestartofthelineandNOTperfectmatch'So, extract a SINGLE character before the start of the find string, and see if is one of these, it is set T = 1 '" "(),.:;+-*/%' = ! < > { } ~ & | # '[]9160' '' the last character of the first match of find string Temp = Mid(DataSource, INSTR(DataSource, Find) - 1, 1) IF IsDivider(Temp) THEN T = 1 if WholeINSTRdebug then print "b"; END IF END IF IF INSTR(DataSource, Find) + LEN(Find) - 1 = LEN(DataSource) THEN 'Ifthefindstringanditslocationinthesearchstringless1isthesameasthesearchstringthen....'Is the a plural check? Is this meant to be the end of string check? T = T + 1 if WholeINSTRdebug then print "c"; End If IF T < 2 THEN 'So,atthispoint..Tcouldbe0or1'So, extract the next SINGLE character after the find position, and see if is one of these, it is increment T '" "(),.:;+-*/%' = ! < > { } ~ & | # '[]9160Temp=Mid(DataSource,INSTR(DataSource,Find)+LEN(Find),1)ifWholeINSTRdebugthenPrint":"+Temp+":";IFIsDivider(Temp)THENT=T+1ifWholeINSTRdebugthenprint"d";ENDIFENDIf'Found 1 condition matched, do it all again if there is another match after the first is removed. IF T = 1 And SearchAgain THEN 'So,swapanyFINDstringforchr(30)anddoitagain.ReplaceDataSource,Find,Chr(30)IFINSTR(DataSource,Find)<>0THENifWholeINSTRdebugthenprint"e";GOTODoWholeINSTRAgainENDIFENDIF'Start of #1199 'So,nomatchforalltheconditions'If there is duplicate search, remove the first occurance IF T = 0 And SearchAgain THEN 'So,swapanyFINDstringforchr(30)anddoitagain.ReplaceDataSource,Find,Chr(30)IFINSTR(DataSource,Find)<>0THENifWholeINSTRdebugthenprint"f";GOTODoWholeINSTRAgainENDIFENDIF'Endof#1199WholeINSTR=TifWholeINSTRdebugthenprint"g"+str(T)ENDFUNCTION
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I'm sorry but I can't offer much by the way of thoughts on your comment as it has gone right over my head. It has gone way too deep for my skillset.
As the resulting variable name of "H1?FS?1" would only be visible in the .asm, with my (more readable) H1Events1 remaining in the source file that would seem to be an elegant solution. {If I've not totally misunderstood that which you are patiently explaining to me}
Or could a warning be generated stating that variable "Events()" has a duplicate declaration of "H1Events1" and requires renaming?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Steve - not to worry. This is intended for those that know the inner works of the compiler.
FYI.. This whole test is just to ensure an (any) array element exists on any line of the user program. You do not see this in the asm as the result is used for this array element existence validation. This way way before any ASM. The area of the compiler that is broken by the functions failure is the part where the compiler optimises the array element when using a constant to an alias (which you do see in the ASM).
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
WholeInstr is there to check if a string contains a substring within it, but with dividers.
The returned value should be 0 if the substring is not in there by itself.
The returned value should be 1 if the substring is in there, but has something before or after it.
The returned value should be 2 if the string is in there with a divider at either side.
So WholeInstr("H1Events1", "Events") should be returning 0, because 1 is not a divider character.
The well named T variable is the output. If the substring is there with a divider (or the start of the string) before it, 1 is added. If the substring is there with a divider (or the end of the string) after it, another 1 is added.
A divider character should be anything that IsDivider says is a divider. The start or end of a string is also treated as a divider, hence the special case for if the substring is the entire string.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
The program below shows the issue. It is not related to the chip family.
#CHIP 18F16Q41
#OPTION EXPLICIT
Dim Events(11)
Dim H1Events1
Events(1)=1
H1Events1 = Events(1)
H1Events1 = Events(2)
H1Events1 = Events(11)
Errors with array not defined
The issue is in the function WholeINSTR.
I have produced a new build 1199 that Steve can test. It has a revised function that should resolve. I am discussing with Hugh but I have submitted the build for release.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I've written a large program for the 16F1829. As it reached the point where it filled 98% of the device (with much work left to do) I switched to the larger and faster 18F15Q40.
The program has been progressing until this afternoon when I added more features, the program was occupying 48% or so of the memory before I sat down after lunch. Having added some extra features, I attempted to compile and was surprised to see that many lines of the program showed errors:
The above relating to line 1818: I've numbered the lines to make things a little clearer (I hope).
With the error(s) stating that the two lines 1818 and 1823, Events(1) being undeclared. There were other errors found, all in the same subroutine, all relating to variables being undeclared.
I was very surprised as I had been using near identical code earlier in the day with zero problems.
Looking at the produced .asm file shows that the references to Events(1) on lines 1818 and 1823 have not been substituted with their "system" variable names, but are referenced to as Events(1). The line 1827 "Let Events(1) = H1Events1 + H2Events1" is compiled correctly, and shows that Events(1) has been assigned the "system" variable name of "SYSEVENTS_1".
.asm for the above code:
I don't think this is down to my terrible coding skills, but have no idea how I can fix this.
I forgot to say that I downloaded the most recent version of GCStudio and it failed with the same errors flagged there too.
I would need the source to figure it out.
Thanks. I've had to email it as it was too large for me to send as a PM. If it doesn't turn up, let me know.
The email truncated the lines of code.
Please send as an attachment.
Apologies, resent. Hopefully correctly this time.
As a workaround change the array Events() to Event_s() Just anything but Event
and, add
Dim PayingCoinAmount as Byte
Seems that Events is reserved on the 18F.
Many, many, many thanks for that. It now, indeed, compiles.
Really odd that I have been using "Events()" on the 18F15Q40 for well over a week (and on the 16F1829 on and off for 2 years or so) with no problems whatsoever. Program compiled and ran on the 18F15Q40 perfectly well up until this afternoon, the earlier version without the mods I made is still running now at work and it uses "Events()" in vast numbers of subroutines. I did a search and replace of "Events(" in the code, it found 66 statements referring to "Events(" all working normally. How very odd.
It is an ambitious, untidy and rather unweildy set of code. I'm far from certain I will actually be able to to get it to work fully. It is for (yet) another Change Machine. In my opinion I've previously built and coded a much, much better design in every way. This is for a replacement PCB (and code) for one of our competitor's machines where their electronic design is electrically unreliable. I'm confident mine will be electrically reliable but not in the least confident I can get the complex software to be reliable. Still, it is a quiet period at work now so I've got time to sit and code 'till my head bursts - which it did today.
See my analysis.
This is not coding related, not chip related, not memory related - see the details below.
I have spent all day trying to find the root cause to the issue.
An update.
Symptom
Error message the an array or array element is not defined.
Error: Variable EVENTS(1) was not explicitly declared
.Examination
The error message states a variable is not defined (not array element) and ASM shows variable usage for a byte variable. However, this is actually defined as an array element in the source program.
H2Events1 = Events(1) movff EVENTS(1),H1EVENTS1
The ASM also show the allocation of a byte memory address for a variable called
EVENT(1)
The use of
EVENT(1)
is a symptom that the program is meant to access an element with the arrayEVENT()
but is it actually accessing a byte variable that has no relation to the array. :-(The user code is impacting the compilation process. The failure is a critical failure that should not occur.
The specific user case follows:
H2Events1 = Events(1)
where the source array name is substring of the target variable AND the array element is a CONSTANT. In this caseINSTR("H2EVENT1", "EVENT") <> 0
so,EVENT
is withinH2EVENT1
.Example Code
yields
Workaround
Ensure the source array name is not a substring of the target variable.
Root Cause
The root cause is deep inside the compiler within a function that examines if a string exists with another string. This is a complex comparison that needs to address maths functions, where a simple INSTR() will not cover the range of use cases.
This specific use case of where the source array name is substring of the target variable ( the error case) does not return the correct value.
The errant line of compiler source is:
WholeINSTR() why it does not match the substring to 2 hence the failure to indentiify the
EVENT(n)
as an array element.The root cause is the function WholeINSTR() . There is no documentation in WholeINSTR() and it may take a many more hours to understand how this function operates to ensure any change does not break other users of WholeINSTR(). WholeINSTR() is used many times across the compiler, so, great care must be taken.
End of report. I will try to fix asap.
Ah...
So that's why it had previously worked well.
All other references to "Events(1)" assigned the result or value to a variable which didn't incorporate the word 'Events" anywhere within the target variable name.
I was trying to assign the variables returned in Events() to a new variable as I knew I would need to update Events() in the following lines of code and wanted to preserve them before they were overwritten. I named them "H1Events1" and H2Events1" (and H1Events2, H2Events2 and so on) so I could more easily recognise the values held by them. Earlier iterations of the code didn't need to reuse "Events()" and so didn't need to save the values in additional variables.
I should add that the suggestion of changing "Events()" to "Event_s()" did work correctly. I've made some major changes to the code and it now is working as I wanted. Been on it all day (again) and the Change Machine is now able to pay the value of inserted coin distributed evenly across two hoppers, halving the time taken to dispense the coins, with any payment errors detected and then corrected where required.
The workaround is valid. As proven by my root cause analysis today.
Well done on the great program!
Trying to fix this for the future is proving to be very hard. I need more eyes on this issue.
I have expanded the function that test for a substring within a string, adding a load of debug, as this has ‘magic’ that is hard to understand what is actually going on.
And, I have added ( between the change number #1199 ) a new test for that is meant to resolve
H1Events1 = Events (1)
orH1Events1 = Events(1)
where the array string search would beEvents
.Findings/Assumption today.
None of the original tests give a score where T > 0
So, is it safe to assume the string exists twice as the 'No match at all - exit with 0 test have been passed – We have at least one match but failed all tests.
So, replace with the FS (#0030) char, and, do it all again.
For this specific use case if becomes H1?FS?1 = Events (1) or H1?FS?1 = Events(1), so, original now work.
Your thoughts please?
Evan
I'm sorry but I can't offer much by the way of thoughts on your comment as it has gone right over my head. It has gone way too deep for my skillset.
As the resulting variable name of "H1?FS?1" would only be visible in the .asm, with my (more readable) H1Events1 remaining in the source file that would seem to be an elegant solution. {If I've not totally misunderstood that which you are patiently explaining to me}
Or could a warning be generated stating that variable "Events()" has a duplicate declaration of "H1Events1" and requires renaming?
Steve - not to worry. This is intended for those that know the inner works of the compiler.
FYI.. This whole test is just to ensure an (any) array element exists on any line of the user program. You do not see this in the asm as the result is used for this array element existence validation. This way way before any ASM. The area of the compiler that is broken by the functions failure is the part where the compiler optimises the array element when using a constant to an alias (which you do see in the ASM).
From Hugh. Documentation.
WholeInstr is there to check if a string contains a substring within it, but with dividers.
The returned value should be 0 if the substring is not in there by itself.
The returned value should be 1 if the substring is in there, but has something before or after it.
The returned value should be 2 if the string is in there with a divider at either side.
Examples:
WholeInstr("ABC", "B") = 0
WholeInstr("AB C", "B") = 1
WholeInstr("A BC", B") = 1
WholeInstr("A B C", "B") = 2
So WholeInstr("H1Events1", "Events") should be returning 0, because 1 is not a divider character.
The well named T variable is the output. If the substring is there with a divider (or the start of the string) before it, 1 is added. If the substring is there with a divider (or the end of the string) after it, another 1 is added.
A divider character should be anything that IsDivider says is a divider. The start or end of a string is also treated as a divider, hence the special case for if the substring is the entire string.
More insights to the issue:
The program below shows the issue. It is not related to the chip family.
The issue is in the function WholeINSTR.
I have produced a new build 1199 that Steve can test. It has a revised function that should resolve. I am discussing with Hugh but I have submitted the build for release.
There is a new test compiler in the GC Studio Dev Channel.
Steve please test. Revert the array naming that caused the issue and please test.
I have, as requested, re-named Event_s() back to Events() and recompiled using the release candidate and the program now compiles and runs normally.
Thanks for all the suggestions given, they really helped.