Home AMX User Forum NetLinx Studio

Baffled by a compiler error

OK, this is driving me crazy. I'm modifying a Marantz UI module, and part of my mod is putting the feedback in a CALL from a TIMELINE. The following snippet is generating a syntax error in the compiler:
DEFINE_CALL 'Panel Feedback'
{
    LOCAL_VAR CHAR sOldFeedback[6][30]
    STACK_VAR CHAR cCount
    
    [dvMarantzTP, nButn[25]] = (nSurroundMode == 0)
    [dvMarantzTP, nButn[26]] = (nSurroundMode == 1)
    [dvMarantzTP, nButn[27]] = (nSurroundMode == 2)
// ...and so on for remainder of call
}
If I comment out the variable declarations and put them in DEFINE_VARIABLE, there is no error. Any attempt to declare them in the CALL itself fails. I've declared variables in CALLs thousands of times, and I am completely baffled as to why I'm getting this error.

I might add, I hate the generic syntax error message with extreme prejudice. It seriously needs to at least provide the token that generated the error. It also pretty consistently highlights the wrong line when you double click the error message. Most of the time I have to comment out lines to pinpoint the real cause of the error because it's not even remotely close to the actual error. In this particular case, it highlights the blank line after the variable declarations; I only know it's the declarations that are causing the problem because commenting them out makes it go away.
«1

Comments

  • Spire_JeffSpire_Jeff Posts: 1,917
    Dave,

    Not sure what is causing the problem, but I had the same issue when pasting you code snippet into a running program. I was able to get the error to disappear by rearranging the code to this:
    DEFINE_CALL 'Panel Feedback'
        LOCAL_VAR CHAR sOldFeedback[6][30]
        STACK_VAR CHAR cCount
    {
        
        [dvMarantzTP, nButn[25]] = (nSurroundMode == 0)
        [dvMarantzTP, nButn[26]] = (nSurroundMode == 1)
        [dvMarantzTP, nButn[27]] = (nSurroundMode == 2)
    // ...and so on for remainder of call
    }
    



    Hope this helps.

    Jeff
  • Don't know why, but if you include some braces it works. The error also disappears when you insert another statement before the feedback statemens

    DEFINE_CALL 'Panel Feedback'
    {
    LOCAL_VAR CHAR sOldFeedback[6][30]
    STACK_VAR CHAR cCount
    {
    [dvMarantzTP, nButn[25]] = (nSurroundMode == 0)
    [dvMarantzTP, nButn[26]] = (nSurroundMode == 1)
    [dvMarantzTP, nButn[27]] = (nSurroundMode == 2)
    }
    // ...and so on for remainder of call
    }

    Or

    DEFINE_CALL 'Panel Feedback'
    {
    LOCAL_VAR CHAR sOldFeedback[6][30]
    STACK_VAR CHAR cCount

    SEND_STRING 0,'something'

    [dvMarantzTP, nButn[25]] = (nSurroundMode == 0)
    [dvMarantzTP, nButn[26]] = (nSurroundMode == 1)
    [dvMarantzTP, nButn[27]] = (nSurroundMode == 2)
    // ...and so on for remainder of call
    }
  • DHawthorneDHawthorne Posts: 4,584
    Sure looks like a glitch in the syntax checker to me...thanks for the replies :).
  • Joe HebertJoe Hebert Posts: 2,159
    I believe the compiler is seeing it as a dimension of an array (ignoring white spaces) which is why inserting any other character after the variable declaration other than [ fixes it.
    [b]You look at it this way:[/b]
    DEFINE_CALL 'Panel Feedback'
    {
        LOCAL_VAR CHAR sOldFeedback[6][30]
        STACK_VAR CHAR cCount
    
        [dvMarantzTP, nButn[25]] = (nSurroundMode == 0)
        [dvMarantzTP, nButn[26]] = (nSurroundMode == 1)
        [dvMarantzTP, nButn[27]] = (nSurroundMode == 2)
    // ...and so on for remainder of call
    }
    
    [b]The compiler looks at it this way and is confused:[/b]
    DEFINE_CALL 'Panel Feedback'
    {
        LOCAL_VAR CHAR sOldFeedback[6][30]
        STACK_VAR CHAR cCount [b][[/b]dvMarantzTP, nButn[25]] = (nSurroundMode == 0)
    
        [dvMarantzTP, nButn[26]] = (nSurroundMode == 1)
        [dvMarantzTP, nButn[27]] = (nSurroundMode == 2)
    // ...and so on for remainder of call
    }
    
    [b]Terminating your statement with a *;* fixes it:[/b]
    DEFINE_CALL 'Panel Feedback'
    {
        LOCAL_VAR CHAR sOldFeedback[6][30]
        STACK_VAR CHAR cCount[b];[/b]
    
        [dvMarantzTP, nButn[25]] = (nSurroundMode == 0)
        [dvMarantzTP, nButn[26]] = (nSurroundMode == 1)
        [dvMarantzTP, nButn[27]] = (nSurroundMode == 2)
    // ...and so on for remainder of call
    }
    

    Joe
  • DHawthorneDHawthorne Posts: 4,584
    I should probably get back in the habit of terminating lines with a semicolon anyway. It took me forever to break the habit from my C++ days when Axcent came along... /sigh.
  • Chip MoodyChip Moody Posts: 727
    Geeze... I can't believe you're still using DEFINE_CALL. :)

    I have the reverse issue with Semicolons. I've always been so used to NOT needing them with AMX - so since C-tron came out with S+, I'm quite often forgetting to add them where they're required...

    - Chip
  • DHawthorneDHawthorne Posts: 4,584
    I use DEFINE_CALL whenever a return value is not required. I know it's miniscule, but I'm sure there is some resource conservation doing it that way - otherwise, I can't imagine there is much difference really.
  • Chip MoodyChip Moody Posts: 727
    I would think the difference between a DEFINE_CALL and a DEFINE_FUNCTION declared without a return type would be miniscule processing-wise, but I would think it would be in favor of the DEFINE_FUNCTION, honestly.

    And the readability plus is just too big to ignore, IMHO.

    CALL 'DoMyFeedback'

    vs.

    DoMyFeedback ()


    Eh, six and one-half dozen the other I suppose...

    - Chip
  • Nice find Joe
    Joe Hebert wrote:
    I believe the compiler is seeing it as a dimension of an array (ignoring white spaces) which is why inserting any other character after the variable declaration other than [ fixes it.

    Joe

    I've seen this one before and never spent enough time to find out the problem. Did AMX Tech Support clue you in? If not, this should be reported.
  • Joe HebertJoe Hebert Posts: 2,159
    Thanks!

    No, I didn?t have any contact with AMX tech support regarding this. I don?t consider this a bug of any type since the compiler is doing its job correctly and terminating statements with a ; fixes any ?misunderstandings? like this. However, it would be nice to have the compiler generate some type of illegal dimension error instead of the generic syntax error message. Although in this particular case the illegal dimension error would have still been confusing since one might assume at first that it was nButn[25] causing the problem since the first feedback line is the one that gets flagged with the error.

    I?ve seen several posts where people point out that the line that the compiler flags is one line off from where the error occurred. I don?t think that?s the case in many instances. For example in the code posted at the top of this thread, the compiler flags the first feedback line as the line with the error. And in this case it?s absolutely true. The compiler flagged the line where the illegal character is actually found.

    About a year ago I had a problem very similar to this and I never figured it out. The only way I fixed it was to swap two lines of code around but it drove me nuts as to why the error disappeared when I did and why I had the error to begin with. So in all honesty it took me about a year to figure out this puzzle. :)


    B_Clements wrote:
    I've seen this one before and never spent enough time to find out the problem. Did AMX Tech Support clue you in? If not, this should be reported.
  • DHawthorneDHawthorne Posts: 4,584
    Understanding exactly how this generated an error has put the whole issue on my radar; I can recall lots of similar problems I have had in the past and simply re-wrote the code to fix it, then moved on and forgot about it.

    What it boils down to, though, is this: if you aren't going to mandate a line termination character, then you cannot universally consider a newline to be white space. I can see how this would be a bit of a nightmare to write into the compiler (and I am am feeling far to lazy to consider what the ruleset would need to be right now :)); which is why termination characters came into being in the first place. Making the compiler "smarter" will also make it less efficient, and since we are (mostly) professionals here, I'm OK with the onus being on the programmer.

    As for the highlight not appearing in the "right" place for the error - that is a bigger issue, and I likewise see no easy solution. My example snippet here left out 20 lines of comments after the variable declaration in question - it wasn't highlighting even remotely close to the error. But that was an easy case; I've seen far worse ones.

    For example: you have a module with a bunch of parameters set in an include file. Errors are highligted based on what the line number would have been if the include was part of the module code. If you have multiple includes (not uncommon for me), it gets to be a royal pain. Throw in a few instances of code spanning multiple lines, and the compiler treating them as one, and then a generic error message, and you have a big problem figuring out what the problem really is. My workaround is very simply, compile often, and structure the way I write code so that I am filling in a legitimately syntaxed framework. That way when an error crops up, at least I know it was something I changed in the last hour if the error message is ambiguous. I would feel better about it all the same, if the compiler always told you exactly what token generated the error. It seems to me it once did - or does it only do so in some cases, and those aren't the kind of slip-ups I make very often? Another pet peeve I have is run-time errors that specify an array indexing error, but not the array name (I really wish NetLinx used zero-based indexing) and/or the the module that generated the error.
  • Spire_JeffSpire_Jeff Posts: 1,917
    I've been following this thread and it makes me wonder... if I start terminating lines with ";", will I relieve some of the errors that drive me up a wall on occasion? The other question that comes to mind would be: Does using a ";" make it easier for the compiler to tell me the line causing the error?

    If the answer is yes to either of the two above questions and Netlinx supports using the ; as a line terminator, why isn't it taught in class to use the ";" to terminate lines?

    Regardless, I think I'm going to untrain my untraining (used to program C and C++) and start using the ";" again. Even if it saves me the trouble of dealing with only one vague error in the future, I think it will be worth it.

    Jeff
  • DHawthorneDHawthorne Posts: 4,584
    I recall from my programing class (many, many moons ago) that it was mentioned you could use a semicolon to terminate lines, but you didn't need to. I also seem to vaguely recall the instructor suggesting it would be a good idea, but it was so long ago I'm not 100% certain.

    My guess is that when they developed the Axcent programming language, they wanted to make it more accessible to those new at programming. They did a good job at that I think; but the semicolon was one of the things they threw out to do that.

    When NetLinx came along, they tried very hard to make it so that old Axcent code could be used with minimal modification, so they likewise left out the requirement for semicolons. Imagine the tedium of going through every snippet of old code and terminating the lines...yak. It would be even worse to add the requirement now, NetLinx code files tending to be much larger and more complex. But I'll be writing all my new code with them.


    ...which leads me to yet another thought: some kind of macro capability in Studio would be truly wonderful, even if only rudimentary. It would make such conversions considerably less onerous.
  • Spire_JeffSpire_Jeff Posts: 1,917
    I agree that they did a great job of developing a language that was easy for novices to use when they developed Axcent. And I don't think they should change the fact that the semicolon is not needed (so as to maintain some compatibity). The idea I was tossing around in my head was: If using the semicolon could possibly cut down on compiler errors and the program supports them, why not teach it and use it as the prefered method? This is more of a question than a request. This entire arguement hinges on the amount of compiler problems that will be fixed by using a semicolon.

    Jeff
  • Chip MoodyChip Moody Posts: 727
    I could see an "enforce semicolons" checkbox in the compiler options, perhaps?

    I'm so used to NOT using semicolons, I wouldn't start unless the compiler was going to check up on me. Otherwise I'd just have <100% of my code with semicolons...

    (And I'm too anal-retentive to allow that)

    - Chip
  • jeffacojeffaco Posts: 121
    Sometimes the NetLinx compiler bugs the crap out of me.

    I'm a "professional" developer. I write high performance, multithreaded servers for a living. When I develop code in C++ (my day job) "offline" (i.e. not regularly compiling), and then I go to compile, I get meaningful error messages, and it's easy for me to determine what the problem is - and where it is. I can get this code up and going quickly.

    When I develop code in NetLinx, I *MUST* regularly compile. Even every dozen lines (or less). If I don't, then sometimes I'll get bizarre errors, and it'll be extraordinarily difficult to isolate.

    When I get bizarre errors, they are generally related to one or more of:

    1. An error message that, in no way, gives me a hint of the actual problem,
    2. Sometimes a declaration (up top) causes a problem down below, in the implementation section. Not clear from error messages,
    3. Line numbers that are inaccurate, forcing me to look at the wrong sections of code.

    It's common for me to comment out blocks of code to help isolate changes when these sorts of things happen.

    Bottom line: I don't think error detection for NetLinx is very good. In the past, I diligently reported these to AMX. Now I just don't bother anymore. I actually gave them *reproducable* issues where the line number was off (and they could reproduce at will), and these still weren't fixed. I just don't think this is a very important issue to AMX (at least judging on their lack of fixing these problems over time, even for easy to reproduce "simple" issues).

    Now, that said: I tend to think that you should just regularly terminate lines with a semi-colon. This is very common in other languages (C, C++, Perl, and many many others). It's much easier for the token analyzer to understand what's coming in, and how to parse. The fact that it sometimes works properly and sometimes doesn't is no surprise to me ...
  • DHawthorneDHawthorne Posts: 4,584
    Ah, you forgot the worst compiler error message of them all! I did this just yesterday, but I've made similar mistakes before that were much harder to track down. It's common for me to store the current source device in a variable I name dvDeck, and use it in conditionals for context-dependent operations. Well, my finger slipped in typing out "IF(dvDeck == dvDVD)," and instead I got "IF(dvDeck ==- dvDVD)." Note the minus sign by the comparator. The error I got was something along the lines of an invalid arithmetical operation on a device - well, OK, that much was good - but double-clicking it to find the error highlighted the device declaration!! Completely worthless for finding the error. If I hadn't known I had a good compile only five minutes ago, it would have been horrible finding wheere that one finger slip was.
  • I played around with this a little, and I believe Joe's right. The compiler is seeing this as the beginning of the dimension of an array.

    However, we fixed a similar problem for lines of code that don't start with an open bracket in v2.2, so if you do something like:
    DEFINE_CALL 'MySubroutine'
    {
        STACK_VAR CHAR cCount
    
        nSurroundMode = 0
    }
    
    ...it will compile just fine in Studio 2.2 and above - well actually, with the v2.2.0.108 compiler that Studio 2.2. installs.

    I'll pass this along to the Engineers...
  • Spire_JeffSpire_Jeff Posts: 1,917
    I was just thinking about the use of semicolons in code and had an interesting thought. It seems to me that it wouldn't be that difficult to write a small routine/tool/app/whatever that would go through the code and simply insert a semicolon a the end of every line as the compiler sees it. If I'm thinking correctly, the compiler already has to figure out where the line ends (which caused the initial problem in this thread), so why not add an option to insert a semicolon just before the end of the line? (Obviously it should check for an existing semicolon to avoid multiple semicolons) This could aid in the debugging process by giving the programmer a somewhat clearer representation of how the compiler is interpreting the code.

    Anyone have any other thoughts on this idea?

    Jeff
  • AMX Compiler

    Jeff
    It seems to me that it wouldn't be that difficult to write a small routine/tool/app/whatever that would go through the code and simply insert a semicolon a the end of every line as the compiler sees it.
    Anyone have any other thoughts on this idea?
    Jeff


    Jeff, I think this would work, as the problem seems to be that the programmer and the compiler see the lines ending in different places.
    If the compiler added the missing semicolons into the source code your idea would let the programmer look through the code that generated the error and show how the compiler saw the code. This should ideally be a compiler option. I never knew you could use semi-colons and always forget them when writing C. Most lines begin with a keyword or a previously declared (and therefore recognizable) variable, so it's easy to see where they start, but multiline DECLARE_VARIABLE statements are an exception. Perhaps semicolons should be obligatory in this case.

    Another cure for the problem of not knowing where array declarations end might be to put in a comment - anyone tried this?
  • Spire_JeffSpire_Jeff Posts: 1,917
    I often comment out the lines in the affected area so that I can narrow my search. Just recently I was encountering problems where the compiler was pointing to line 567 and the error really occured in line 566 or 565. I tried the semi colons first, but then had to comment out to find the error. It was related to an array variable that had 2 elements and I was only providing 1.

    Jeff
  • Terminating Array Declarations

    Jeff

    What I meant was to put a comment at the end of the array declaration instead of a semi-colon, so to tell the compiler where it ended.

    John
  • DHawthorneDHawthorne Posts: 4,584
    Jeff

    What I meant was to put a comment at the end of the array declaration instead of a semi-colon, so to tell the compiler where it ended.

    John
    But comments don't even exist as far as the compiler is concerned. It would not interpret the existence of a comment as the end of the declaration. You can put a comment smack-dab in the middle of a declaration without affecting it, as long as it doesn't actually interupt the identifier itself.
  • deadkendeadken Posts: 10
    The problem is the language's grammer is ambiguous. It would be interesting to see them try to pump it through something like yacc.

    Where I always seem to get burned is in returns without values. The compiler always takes the next statement as the value. I end up surrounding it with {} to get rid of errors.
  • Greetings everyone!

    I tried to play around with this block and found out curious thing:

    DEFINE_CALL 'NO NAME'
    STACK_VAR no_Name1
    STACK_VAR no_Name2
    {
    //SO SOMETHING
    //WITH NONAMES
    }

    works fine, also if there's only one declaration per call it works the way it was posted originally:

    DEFINE_CALL 'NO NAME'
    {
    STACK_VAR no_Name1

    //SO SOMETHING
    //WITH NONAME
    }

    But if you have more than one, it doesn't
    DEFINE_CALL 'NO NAME'
    {
    STACK_VAR no_Name1
    STACK_VAR no_Name2

    //SO SOMETHING
    //WITH NONAME
    }

    will return compiler error. According to Netlinx Programming Language description:
    "...Local
    variables must be declared immediately after the opening brace of a block but before the
    first executable statement."

    So, compiler thinks, that second STACK_VAR is the "...first executable statement." Braces before STACK_VAR:

    DEFINE_CALL 'NO NAME'
    {
    STACK_VAR no_Name1
    STACK_VAR no_Name2
    {
    //SO SOMETHING
    //WITH NONAMES
    }
    }

    tell compiler where is the beginning of the first executable statement. It makes some sense to me, because it looks a little bit like other language elemnts, e.g. IF:

    ...
    IF (SOMETHING_IS_WRONG)
    SEND_STRING SOMEONE, "'DO SOMETHING'"
    SEND_STRING SOMEONE, "'DO SOMETHING ELSE'"

    first 'DO SOMETHING' is executed as a part of conditional because it's the first statement right after 'IF'.

    Anyway, it's just my toughts.

    Good luck everyone.
  • a_riot42a_riot42 Posts: 1,624
    I haven't come across this issue as I don't do feedback using this method, but I like the fact that no semicolons are required in Netlinx. Missing or misplaced semicolon errors are much more common in languages that require them. If this bug is the only price paid for no semicolons I'm happy to pay it.
    Paul
  • travtrav Posts: 188
    ZOMBIE!

    Best bit of thread necromancy I've seen in a long while!
  • AuserAuser Posts: 506
    I played around with this a little, and I believe Joe's right. The compiler is seeing this as the beginning of the dimension of an array.

    [...]

    I'll pass this along to the Engineers...

    I'm glad someone did dig this up. This caught me out the other day and wasted half an hour of my time. 3 years (at least) since the problem was identified and it still hasn't been fixed?!

    Edit: Me no can add. Make that 4 years!
  • Auser wrote: »
    I'm glad someone did dig this up. This caught me out the other day and wasted half an hour of my time. 3 years (at least) since the problem was identified and it still hasn't been fixed?!

    Edit: Me no can add. Make that 4 years!

    And I got caught with it today. This stuff is getting irritating.

    --John
  • Whitespace

    I think someone already mentioned this, but...

    There is no required End-Of-Line delimiter in NetLinx, so to the compiler the two code snippets below are the same:
    // start
    STACK_VAR INTEGER nMyInt[<...additional code here>
    // end

    //start
    STACK_VAR INTEGER nMyInt
    [<...additional code here>
    // end

    My guess is this one of those things that doesn't have any easy or elegant fix that won't break someone else's existing code.
Sign In or Register to comment.