⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parserthread.cpp

📁 非常好用的可移植的多平台C/C++源代码编辑器
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    //                    Log("peek='::', token='" + token + "', m_LastToken='" + m_LastToken + "', m_Str='" + m_Str + "'");
                        m_EncounteredNamespaces.Add(token);
                        m_Tokens.GetToken(); // eat ::
                    }
                    if (m_Str.IsEmpty())
                    {
                        m_Str = GetStringFromArray(m_EncounteredNamespaces, _T("::")) + token;
                        m_EncounteredNamespaces.Clear();
                    }
				}
                else if (peek.Matches(_T("::")))
                {
//                    Log("peek='::', token='" + token + "', m_LastToken='" + m_LastToken + "', m_Str='" + m_Str + "'");
                    m_EncounteredNamespaces.Add(token);
                    m_Tokens.GetToken(); // eat ::
                }
				else if ((peek.Matches(_T(";")) || (m_Options.useBuffer && peek.GetChar(0) == _T('(')) && !m_Str.Contains(_T("::"))) && m_pTokens)
				{
//					Log("m_Str='"+m_Str+"'");
//					Log("token='"+token+"'");
//					Log("peek='"+peek+"'");
					if (!m_Str.IsEmpty() && (isalpha(token.GetChar(0)) || token.GetChar(0) == '_'))
					{
                        DoAddToken(tkVariable, token);
                    }
					//m_Str.Clear();
				}
				else
				{
					m_Str << token << _T(" ");
				}
			}
		}
		m_LastToken = token;
	}
	return true;
}

Token* ParserThread::TokenExists(const wxString& name, Token* parent, short int kindMask)
{
    if (!m_pTokens)
        return 0;
    if (!parent)
    {
        // when parsing a block, we must make sure the token does not already exist...
        for (unsigned int i = m_StartBlockIndex; i < m_pTokens->GetCount(); ++i)
        {
            Token* token = m_pTokens->Item(i);
            if ((token->m_TokenKind & kindMask) && token->m_Name.Matches(name))
                return token;
        }
    }
    else
    {
        // search only under the parent token
        for (unsigned int i = 0; i < parent->m_Children.GetCount(); ++i)
        {
            Token* token = parent->m_Children.Item(i);
            if ((token->m_TokenKind & kindMask) && token->m_Name.Matches(name))
                return token;
        }
    }
	return 0L;
}

wxString ParserThread::GetActualTokenType()
{
    // we will compensate for spaces between
    // namespaces (e.g. NAMESPACE :: SomeType) wich is valid C++ construct
    // we 'll remove spaces that follow a semicolon
	int pos = 0;
	while (pos < (int)m_Str.Length())
	{
        if (m_Str.GetChar(pos) == ' ' &&
            (
                (pos > 0 && m_Str.GetChar(pos - 1) == ':') ||
                (pos < (int)m_Str.Length() - 1 && m_Str.GetChar(pos + 1) == ':')
            )
           )
        {
            m_Str.Remove(pos, 1);
        }
        else
            ++pos;
	}

	// m_Str contains the full text before the token's declaration
	// an example m_Str value would be: const wxString&
	// what we do here is locate the actual return value (wxString in this example)
	// it will be needed by code completion code ;)
	pos = m_Str.Length() - 1;
	// we walk m_Str backwards until we find a non-space character which also is
	// not * or &
	//                        const wxString&
	// in this example, we would stop here ^
    while (pos >= 0 &&
            (isspace(m_Str.GetChar(pos)) ||
            m_Str.GetChar(pos) == '*' ||
            m_Str.GetChar(pos) == '&'))
        --pos;
	if (pos >= 0)
	{
		// we have the end of the word we 're interested in
		int end = pos;
		// continue walking backwards until we find the start of the word
		//                               const wxString&
		// in this example, we would stop here ^
        while (pos >= 0 && (isalnum(m_Str.GetChar(pos)) || m_Str.GetChar(pos) == '_' || m_Str.GetChar(pos) == ':'))
            --pos;
		return m_Str.Mid(pos + 1, end - pos);
	}
	return wxEmptyString;
}

Token* ParserThread::DoAddToken(TokenKind kind, const wxString& name, const wxString& args, bool isOperator)
{
	wxMutexLocker lock(s_mutexProtection);
	if (m_Options.useBuffer && TokenExists(name))
		return 0L;
	Token* newToken = new Token;
	m_Str.Trim();
	if (kind == tkDestructor)
	{
		// special class destructors case
		newToken->m_Name = _T("~") + name;
		m_Str.Clear();
	}
	else
		newToken->m_Name = name;

    // check for implementation member function
    Token* localParent = 0;
    if (m_EncounteredNamespaces.GetCount())
    {
        unsigned int count = m_EncounteredNamespaces.GetCount();
        for (unsigned int i = 0; i < count; ++i)
        {
//            Log("NS: '" + m_EncounteredNamespaces[i] + "' for " + newToken->m_Name);
            localParent = TokenExists(m_EncounteredNamespaces[i], localParent, tkClass | tkNamespace);
            if (!localParent)
                break;
        }
        m_EncounteredNamespaces.Clear();
    }
    if (localParent)
    {
//        Log("Parent found for " + m_Str + " " + newToken->m_Name + ": " + localParent->m_DisplayName);
        Token* existing = TokenExists(newToken->m_Name, localParent);
        if (existing)
        {
//            Log("Existing found for " + newToken->m_Name);
            // if the token exists, all we have to do is adjust the
            // implementation file/line
            existing->m_ImplFilename = m_Tokens.GetFilename();
            existing->m_ImplLine = m_Tokens.GetLineNumber();
            delete newToken;
            return existing;
        }
    }

	newToken->m_Type = m_Str;
	newToken->m_ActualType = GetActualTokenType();
	newToken->m_Args = args;
	newToken->m_Scope = m_LastScope;
	newToken->m_TokenKind = kind;
	newToken->m_IsLocal = m_IsLocal;
	newToken->m_pParent = m_pLastParent;
	newToken->m_Filename = m_Tokens.GetFilename();
	newToken->m_Line = m_Tokens.GetLineNumber();
	newToken->m_ImplLine = 0;
	newToken->m_IsOperator = isOperator;
	newToken->m_IsTemporary = m_Options.useBuffer;
//    Log("Added token " +name+ ", type '" +newToken->m_Type+ "', actual '" +newToken->m_ActualType+ "'");
	if (m_pLastParent)
		newToken->m_DisplayName << m_pLastParent->m_Name << _T("::");
	newToken->m_DisplayName << newToken->m_Name << args;
	if (!newToken->m_Type.IsEmpty())
		newToken->m_DisplayName << _T(" : ") << newToken->m_Type;

    if (m_pTokens)
        m_pTokens->Add(newToken);
    if (m_pLastParent)
        m_pLastParent->AddChild(newToken);

	return newToken;
}

void ParserThread::HandleIncludes()
{
	wxString filename;
	bool isGlobal = !m_IsLocal;
	wxString token = m_Tokens.GetToken();
	// now token holds something like:
	// "someheader.h"
	// < and will follow iostream.h, >
	if (!token.IsEmpty())
	{
		if (token.GetChar(0) == '"')
		{
			// "someheader.h"
			token.Replace(_T("\""), _T(""));
			filename = token;
		}
		else if (token.GetChar(0) == '<')
		{
			isGlobal = true;
			// next token is filename, next is . (dot), next is extension
			// basically we 'll loop until >
			while (1)
			{
				token = m_Tokens.GetToken();
				if (token.IsEmpty())
					break;
				if (token.GetChar(0) != '>')
					filename << token;
				else
					break;
			}
		}
	}

	if (!filename.IsEmpty())
	{
		wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, FILE_NEEDS_PARSING);
		event.SetString(m_Filename + _T("+") + filename);
		// setting all #includes as global
		// it's amazing how many projects use #include "..." for global headers (MSVC mainly - booh)
		event.SetInt(1);//isGlobal);
//		wxPostEvent(m_pParent, event);

        // since we 'll be calling directly the parser's method, let's make it thread-safe
		static wxMutex lock;
		wxMutexLocker l(lock);
		m_pParent->ProcessEvent(event);
	}
}

void ParserThread::HandleDefines()
{
	wxString filename;
	wxString token = m_Tokens.GetToken();
	m_Str.Clear();
	// now token holds something like:
	// BLAH_BLAH
	if (!token.IsEmpty())
	{
        // make sure preprocessor definitions are not going under namespaces or classes!
        Token* oldParent = m_pLastParent;
        m_pLastParent = 0L;

		Token* newToken = DoAddToken(tkPreprocessor, token);
		if (newToken)
            newToken->m_Line -= 1; // preprocessor definitions need correction for the line number
		if (m_Tokens.PeekToken().GetChar(0) == '(') // TODO: find better way...
			m_Tokens.GetToken(); // eat args

        m_pLastParent = oldParent;
	}
}

void ParserThread::HandleNamespace()
{
    wxString ns = m_Tokens.GetToken();
    wxString next = m_Tokens.PeekToken();

    if (next.Matches(_T("{")))
    {
        // use the existing copy (if any)
        Token* newToken = TokenExists(ns, 0, tkNamespace);
        if (!newToken)
            newToken = DoAddToken(tkNamespace, ns);
        if (!newToken)
            return;

        m_Tokens.GetToken(); // eat {

        Token* lastParent = m_pLastParent;
        TokenScope lastScope = m_LastScope;

        m_pLastParent = newToken;
        // default scope is: public for namespaces (actually no, but emulate it)
        m_LastScope = tsPublic;

        Parse();

        m_pLastParent = lastParent;
        m_LastScope = lastScope;
    }
    else
        SkipToOneOfChars(_T(";{")); // some kind of error in code ?
}

void ParserThread::HandleClass(bool isClass)
{
    int lineNr = m_Tokens.GetLineNumber();
	wxString ancestors;
	while (1)
	{
		wxString current = m_Tokens.GetToken();
		wxString next = m_Tokens.PeekToken();
		if (!current.IsEmpty() && !next.IsEmpty())
		{
			if (next.Matches(_T("<"))) // template specialization
			{
                SkipAngleBraces();
                next = m_Tokens.PeekToken();
			}

			if (next.Matches(_T(":"))) // has ancestor(s)
			{
                //Log("Class " + current + " has ancestors");
				m_Tokens.GetToken(); // eat ":"
				while (1)
				{
					wxString tmp = m_Tokens.GetToken();
					next = m_Tokens.PeekToken();
					if (!tmp.Matches(_T("public")) &&
						!tmp.Matches(_T("protected")) &&
						!tmp.Matches(_T("private")) &&
						!tmp.Matches(_T(">")) &&
						!tmp.Matches(_T(",")))
                    {
                        // fix for namespace usage in ancestors
                        if (tmp.Matches(_T("::")) || next.Matches(_T("::")))
                            ancestors << tmp;
						else
                            ancestors << tmp << _T(',');
						//Log("Adding ancestor " + tmp);
                    }
					if (next.IsEmpty() ||
						next.Matches(_T("{")) ||
						next.Matches(_T(";")))
						break;
                    else if (next.Matches(_T("<")))
                    {
                        // template class
                        int nest = 0;
                        m_Tokens.GetToken(); // eat "<"
                        while (1)
                        {
                            wxString tmp1 = m_Tokens.GetToken();
                            if (tmp1.Matches(_T("<")))
                                ++nest;
                            else if (tmp1.Matches(_T(">")))
                                --nest;

                            if (tmp1.IsEmpty() ||
                                tmp1.Matches(_T("{")) ||
                                tmp1.Matches(_T(";")) ||
                                (tmp1.Matches(_T(">")) && nest <= 0))
                            {
                                m_Tokens.UngetToken(); // put it back before exiting
                                break;
                            }
                        }
                    }
				}
                //Log("Ancestors: " + ancestors);
			}

			if (current.Matches(_T("{"))) // unnamed class/struct
			{
				Token* lastParent = m_pLastParent;
				TokenScope lastScope = m_LastScope;

				// default scope is: private for classes, public for structs
				m_LastScope = isClass ? tsPrivate : tsPublic;

				Parse();

				m_pLastParent = lastParent;
				m_LastScope = lastScope;
                break;
			}
			else if (next.Matches(_T("{")))   // no ancestor(s)
			{
				Token* newToken = DoAddToken(tkClass, current);
				if (!newToken)
					return;
                newToken->m_Line = lineNr; // correct line number (might be messed if class has ancestors)
				newToken->m_AncestorsString = ancestors;

                m_Tokens.GetToken(); // eat {

				Token* lastParent = m_pLastParent;
				TokenScope lastScope = m_LastScope;

				m_pLastParent = newToken;
				// default scope is: private for classes, public for structs
				m_LastScope = isClass ? tsPrivate : tsPublic;

				Parse();

				m_pLastParent = lastParent;
				m_LastScope = lastScope;
                break;
			}
			else if (next.Matches(_T(";"))) // forward decl; we don't care
				break;
			else if (next.GetChar(0) == '(') // function: struct xyz& DoSomething()...
			{
				HandleFunction(current);
				break;
			}
		}
		else
			break;
	}
}

void ParserThread::HandleFunction(const wxString& name, bool isOperator)
{
    //Log("Adding function '"+name+"': m_Str='"+m_Str+"'");
	wxString args = m_Tokens.GetToken();
	if (!m_Str.StartsWith(_T("friend")))
	{
		TokenKind kind = tkFunction;
		bool CtorDtor = m_pLastParent && name.Matches(m_pLastParent->m_Name);
		if (!CtorDtor)
		{
            // check for m_EncounteredNamespaces
            unsigned int count = m_EncounteredNamespaces.GetCount();
            if (count)
            {
                Token* localParent = 0;
                for (unsigned int i = 0; i < count; ++i)
                {
                    localParent = TokenExists(m_EncounteredNamespaces[i], localParent, tkClass | tkNamespace);
                    if (!localParent)
                        break;
                }
                CtorDtor = localParent && name.Matches(localParent->m_Name);
            }
		}

		if (CtorDtor)
		{
			m_Str.Trim();
			if (m_Str.IsEmpty())
				kind = tkConstructor;
			else if (m_Str.Matches(_T("~")))
				kind = tkDestructor;
		}
//        Log("Adding function '"+name+"': m_Str='"+m_Str+"'"+", enc_ns="+(m_EncounteredNamespaces.GetCount()?m_EncounteredNamespaces[0]:"nil"));
		DoAddToken(kind, name, args, isOperator);
	}
	if (!m_Tokens.PeekToken().Matches(_T("}")))
		SkipToOneOfChars(_T(";}"), true);
}

void ParserThread::HandleEnum()
{
	// enums have the following rough definition:
	// enum [xxx] { type1 name1 [= 1][, [type2 name2 [= 2]]] };
	bool isUnnamed = false;
	wxString token = m_Tokens.GetToken();
	if (token.IsEmpty())
		return;
    else if (token.Matches(_T("{")))
	{
        // we have an un-named enum
		token = _T("Un-named");
		m_Tokens.UngetToken(); // return '{' back
		isUnnamed = true;
    }

	Token* newEnum = 0L;
	unsigned int level = 0;
	if (isalpha(token.GetChar(0)))
	{
		if (m_Tokens.PeekToken().GetChar(0) != '{')
			return;

        if (isUnnamed)
        {
            // for unnamed enums, look if we already have "Unnamed", so we don't
            // add a new one for every unnamed enum we encounter, in this scope...
            newEnum = TokenExists(token, m_pLastParent, tkEnum);
        }

        if (!newEnum) // either named or first unnamed enum
            newEnum = DoAddToken(tkEnum, token);
		level = m_Tokens.GetNestingLevel();
		m_Tokens.GetToken(); // skip {
	}
	else
	{
		if (token.GetChar(0) != '{')
			return;
		level = m_Tokens.GetNestingLevel() - 1; // we 've already entered the { block
	}

	while (1)
	{
		// process enumerators
		token = m_Tokens.GetToken();
		wxString peek = m_Tokens.PeekToken();
		if (token.IsEmpty() || peek.IsEmpty())
			return; //eof
		if (token.Matches(_T("}")) && level == m_Tokens.GetNestingLevel())
			break;
		// assignments (=xxx) are ignored by the tokenizer,
		// so we don't have to worry about them here ;)
		if (peek.Matches(_T(",")) || peek.Matches(_T("}")) || peek.Matches(_T(":")))
		{
            // this "if", avoids non-valid enumerators
            // like a comma (if no enumerators follow)
            if (isalpha(token.GetChar(0)))
            {
                Token* lastParent = m_pLastParent;
                m_pLastParent = newEnum;
                DoAddToken(tkEnumerator, token);
                m_pLastParent = lastParent;
			}
			if (peek.Matches(_T(":")))
			{
				// bit specifier (eg, xxx:1)
				//walk to , or }
				SkipToOneOfChars(_T(",}"));
			}
		}
	}
	// skip to ;
	token = m_Tokens.GetToken();
	while (!token.IsEmpty() && !token.Matches(_T(";")))
		token = m_Tokens.GetToken();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -