News:

As usual while waiting for the next release - don't forget to check the nightly builds in the forum.

Main Menu

extern "C" not working with CC

Started by daniloz, February 11, 2011, 01:40:40 PM

Previous topic - Next topic

daniloz

Hi All,

I have some function in assembly (on a DSP project) and I use the following syntax to declare them in C++:
extern "C" void foo_asm(...);

However, the CC is not recognizing this declaration because of the ' "C" ' part... Here is a small example to reproduce this:

extern "C" void  foo_asm(void);

extern void  foo_OK(void);

void main()
{
foo
}

If you place the cursor after foo in main, you just get "foo_OK" as suggestion and foo_asm doesn't even appears in the symbol browser...

Any hints or workarounds ?

ollydbg

it can be fix very easily. I have see someone complain this before.
But the question is: Is it necessary???
Because currently, extern statement was skipped by CC's parser.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

daniloz

Quote from: ollydbg on February 11, 2011, 02:05:01 PM
it can be fix very easily. I have see someone complain this before.
That's good news!

Quote from: ollydbg on February 11, 2011, 02:05:01 PM
But the question is: Is it necessary???
Because currently, extern statement was skipped by CC's parser.
I don't think this is the case, if you look at my example, foo_OK is processed by the CC and shown in the Symbol Browse AND as a completion suggestion.

In my case it would be VERY convenient to have these external processed because then I can get the argument list while typing... :-)

By the way, I'd be more than happy to do the patch on my system and try it, if you point me to the right direction... ;-)

ollydbg

Oh, sorry, I just review the code in "parserthread.cpp"

            else if (token == ParserConsts::kw_extern)
            {
                // check for "C", "C++"
                m_Str = m_Tokenizer.GetToken();
                if (m_Str == ParserConsts::kw_C || m_Str == ParserConsts::kw_CPP)
                {
                    m_Tokenizer.GetToken(); // "eat" {
                    DoParse(); // time for recursion ;)
                }
                else
                {
                    // do nothing, just skip keyword "extern", otherwise uncomment:
                    //SkipToOneOfChars(ParserConsts::semicolon); // skip externs
                    m_Tokenizer.UngetToken();
                }
                m_Str.Clear();
            }

It seems you are right, the feature was not implemented. :D

It may be a bug, see the statement:
m_Tokenizer.GetToken(); // "eat" {
I think we need to check the Token is a "{" or not, am I right?
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

daniloz

Quote from: ollydbg on February 11, 2011, 03:18:28 PM
It seems you are right, the feature was not implemented. :D
That's great news, actually... :-D

Quote from: ollydbg on February 11, 2011, 03:18:28 PM
It may be a bug, see the statement:
m_Tokenizer.GetToken(); // "eat" {
I think we need to check the Token is a "{" or not, am I right?
Yes, it can be a simple statement as in my example case... How do we do this check? (I am new to the CC code, sorry)

BTW, I changed by example to

extern "C" {void  foo_asm(void);}

extern void  foo_OK(void);

void main()
{
foo
}

And now I get the completion for both foo_OK and foo_asm. :-)

However, I'd still prefer to not to have to use {}s...

Loaden

It should been fixed in next nightly build.

ollydbg

Quote from: daniloz on February 11, 2011, 03:39:13 PM
Quote from: ollydbg on February 11, 2011, 03:18:28 PM
It may be a bug, see the statement:
m_Tokenizer.GetToken(); // "eat" {
I think we need to check the Token is a "{" or not, am I right?
Yes, it can be a simple statement as in my example case... How do we do this check? (I am new to the CC code, sorry)
Aha, it was quite simple.


// check for "C", "C++"
               m_Str = m_Tokenizer.GetToken();
               if (m_Str == ParserConsts::kw_C || m_Str == ParserConsts::kw_CPP)
               {
                   wxString a;
                   a = m_Tokenizer.PeekToken();
                   if(a=="{")
                   {
                        m_Tokenizer.GetToken(); // "eat" {
                        DoParse(); // time for recursion ;)
                   }
                   else
                   {

                         // which means it is in your case, not a "{"
                        // such as: extern "C" void foo_asm(...);
                        // a == "void"
                        //do nothing here, so, both "extern" and "C" was skipped transparently.
                       
                   }
               }
               else
               {
                   // do nothing, just skip keyword "extern", otherwise uncomment:
                   //SkipToOneOfChars(ParserConsts::semicolon); // skip externs
                   m_Tokenizer.UngetToken();
               }
               m_Str.Clear();

 


This is a brief algorithm in my mind, I haven't much time to test it, but I think you can test it. :D
remember:
GetToken() just eat the next Token
PeekToken() just do a peek at the next Token, but NOT eat the next Token.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.

daniloz

Quote from: ollydbg on February 11, 2011, 03:59:50 PM
This is a brief algorithm in my mind, I haven't much time to test it, but I think you can test it. :D
remember:
GetToken() just eat the next Token
PeekToken() just do a peek at the next Token, but NOT eat the next Token.
Thanks for the fix and for the explanation, the only thing I changed is that I used ParserConsts::opbrace instead of "{", so I have the following code, which works 100%!! :-)

else if (token == ParserConsts::kw_extern)
            {
                // check for "C", "C++"
                m_Str = m_Tokenizer.GetToken();
                if (m_Str == ParserConsts::kw_C || m_Str == ParserConsts::kw_CPP)
                {
                wxString a = m_Tokenizer.PeekToken();
                if (a == ParserConsts::opbrace)
{
m_Tokenizer.GetToken(); // "eat" {
DoParse(); // time for recursion ;)
}
else
{ // here we have something like extern "C" void foo_asm(...);
                                // a == "void"
} //do nothing here, so, both "extern" and "C" was skipped transparently.
                }
                else
                {
                    // do nothing, just skip keyword "extern", otherwise uncomment:
                    //SkipToOneOfChars(ParserConsts::semicolon); // skip externs
                    m_Tokenizer.UngetToken();
                }
                m_Str.Clear();
            }

ollydbg

@loaden
I think the rev 6984 has some problems, even the "{" is skipped, Doparse() will still be called. This is not necessary.
If some piece of memory should be reused, turn them to variables (or const variables).
If some piece of operations should be reused, turn them to functions.
If they happened together, then turn them to classes.