📄 parserthread.cpp
字号:
/*
* This file is part of Code::Blocks Studio, an open-source cross-platform IDE
* Copyright (C) 2003 Yiannis An. Mandravellos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact e-mail: Yiannis An. Mandravellos <mandrav@codeblocks.org>
* Program URL : http://www.codeblocks.org
*
* $Id: parserthread.cpp,v 1.22.2.1 2005/10/25 07:59:01 mandrav Exp $
* $Date: 2005/10/25 07:59:01 $
*/
#include <sdk.h>
#include "parserthread.h"
#include <wx/app.h>
#include <wx/log.h>
#include <wx/msgdlg.h>
#include <globals.h>
#include <cctype>
int THREAD_START = wxNewId();
int THREAD_END = wxNewId();
int NEW_TOKEN = wxNewId();
int FILE_NEEDS_PARSING = wxNewId();
ParserThread::ParserThread(wxEvtHandler* parent,bool* abortflag,
const wxString& bufferOrFilename,
bool isLocal,
ParserThreadOptions& options,
TokensArray* tokens)
: m_pParent(parent),
m_pTokens(tokens),
m_pLastParent(0L),
m_IsLocal(isLocal),
m_StartBlockIndex(0),
m_Options(options)
{
// m_pAbort=abortflag;
//ctor
m_Tokens.m_Options.wantPreprocessor = options.wantPreprocessor;
if (!bufferOrFilename.IsEmpty())
{
if (!options.useBuffer)
{
m_Filename = bufferOrFilename;
m_Tokens.Init(m_Filename);
}
else
m_Tokens.InitFromBuffer(bufferOrFilename);
}
m_LastScope = tsUndefined;
}
ParserThread::~ParserThread()
{
//dtor
}
void ParserThread::Log(const wxString& log)
{
wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, NEW_TOKEN);
event.SetString(log);
event.SetInt(m_Tokens.GetLineNumber());
wxPostEvent(m_pParent, event);
wxYield();
}
void ParserThread::SetTokens(TokensArray* tokens)
{
m_pTokens = tokens;
}
void* ParserThread::DoRun()
{
// wxCommandEvent event(wxEVT_COMMAND_MENU_SELECTED, THREAD_START);
// event.SetString(m_Filename);
// event.SetInt((int)this);
// wxPostEvent(m_pParent, event);
//
//// Log("ParserThread running for " + m_Filename);
// Parse();
//
// wxCommandEvent event1(wxEVT_COMMAND_MENU_SELECTED, THREAD_END);
// event1.SetString(m_Filename);
// event1.SetInt((int)this);
// wxPostEvent(m_pParent, event1);
return 0L;
}
wxChar ParserThread::SkipToOneOfChars(const wxString& chars, bool supportNesting)
{
unsigned int level = m_Tokens.GetNestingLevel();
while (1)
{
wxString token = m_Tokens.GetToken();
if (token.IsEmpty())
return '\0'; // eof
if (!supportNesting ||
(supportNesting && m_Tokens.GetNestingLevel() == level))
{
wxChar ch = token.GetChar(0);
if (chars.Find(ch) != wxNOT_FOUND)
return ch;
}
}
}
void ParserThread::SkipBlock()
{
// skip tokens until we reach }
// block nesting is taken into consideration too ;)
// this is the nesting level we start at
// we subtract 1 because we 're already inside the block
// (since we 've read the {)
unsigned int level = m_Tokens.GetNestingLevel() - 1;
while (1)
{
wxString token = m_Tokens.GetToken();
if (token.IsEmpty())
break; // eof
// if we reach the initial nesting level, we are done
if (level == m_Tokens.GetNestingLevel())
break;
}
}
void ParserThread::SkipAngleBraces()
{
int nestLvl = 0;
while (true)
{
wxString tmp = m_Tokens.GetToken();
if (tmp.Matches(_T("<")))
++nestLvl;
else if (tmp.Matches(_T(">")))
--nestLvl;
else if (tmp.Matches(_T(";")))
{
// unget token - leave ; on the stack
m_Tokens.UngetToken();
break;
}
else if (tmp.IsEmpty())
break;
if (nestLvl <= 0)
break;
}
}
bool ParserThread::ParseBufferForFunctions(const wxString& buffer)
{
if (!m_pTokens)
return false;
m_pTokens->Clear();
m_Tokens.InitFromBuffer(buffer);
if (!m_Tokens.IsOK())
return false;
m_Str.Clear();
m_EncounteredNamespaces.Clear();
while (1)
{
if (!m_pTokens || TestDestroy())
return false;
wxString token = m_Tokens.GetToken();
if (token.IsEmpty())
break;
#if 0
if (!m_Str.IsEmpty())
Log(m_Str);
#endif
#if 0
if (!token.IsEmpty())
Log(token);
#endif
if (token.Matches(_T(";")))
{
m_Str.Clear();
}
else if (token.Matches(_T("{")))
{
SkipBlock();
m_Str.Clear();
}
else if (token.Matches(_T("}")))
{
m_Str.Clear();
}
// else if (token.Matches("::"))
// {
// m_Str.Clear();
// }
else if (token.Matches(_T("typedef")) ||
token.Matches(_T(":")))
{
SkipToOneOfChars(_T(";}"), true);
m_Str.Clear();
}
else if (token.Matches(_T("extern")) ||
token.StartsWith(_T("__asm")))
{
SkipToOneOfChars(_T(";"));
//m_Str.Clear();
}
else if (token.Matches(_T("#")))
{
m_Tokens.GetToken();
m_Tokens.GetToken();
m_Str.Clear();
}
else
{
wxString peek = m_Tokens.PeekToken();
if (!peek.IsEmpty())
{
if (peek.GetChar(0) == '(')
{
// function
// ignore some well-known wxWindows macros
if (token.Matches(_T("BEGIN_EVENT_TABLE")))
{
// skip till after END_EVENT_TABLE
while (!token.IsEmpty() && !token.Matches(_T("END_EVENT_TABLE")))
token = m_Tokens.GetToken(); // skip args
m_Tokens.GetToken(); // skip args
}
else if (!token.Matches(_T("*_EVENT_TABLE")) &&
!token.Matches(_T("IMPLEMENT_APP")) &&
!token.Matches(_T("WX_DECLARE_*")) &&
!token.Matches(_T("WX_DEFINE_*")))
{
if (m_Str.GetChar(0) == '~')
{
token = _T('~') + token;
m_Str.Clear();
}
HandleFunction(token);
}
else
m_Tokens.GetToken(); // skip args
}
else
{
m_Str << token << _T(" ");
}
}
}
}
return true;
}
bool ParserThread::Parse()
{
if (!m_pTokens)
return false;
#if 0
if (!m_Options.useBuffer)
Log("Parsing " + m_Filename);
#endif
if (!m_Tokens.IsOK())
{
//Log("Cannot parse " + m_Filename);
return false;
}
if (m_Options.useBuffer)
m_StartBlockIndex = m_pTokens->GetCount();
else
m_StartBlockIndex = 0;
m_Str.Clear();
m_LastToken.Clear();
m_EncounteredNamespaces.Clear();
while (1)
{
if (!m_pTokens || TestDestroy())
break;
wxString token = m_Tokens.GetToken();
if (token.IsEmpty())
break;
#if 0
if (!m_Str.IsEmpty())
Log(m_Str);
#endif
#if 0
if (!token.IsEmpty())
Log(token);
#endif
if (token.Matches(_T(";")))
{
m_Str.Clear();
}
else if (token.Matches(_T("delete")) ||
token.Matches(_T(".")) ||
(token.Matches(_T(">")) && m_LastToken.Matches(_T("-"))))
{
m_Str.Clear();
SkipToOneOfChars(_T(";}"));
}
else if (token.Matches(_T("{")))
{
if (!m_Options.useBuffer || m_Options.bufferSkipBlocks)
SkipBlock();
m_Str.Clear();
}
else if (token.Matches(_T("}")))
{
m_pLastParent = 0L;
m_LastScope = tsUndefined;
m_Str.Clear();
// the only time we get to find a } is when recursively called by e.g. HandleClass
// we have to return now...
if (!m_Options.useBuffer)
break;
}
else if (token.Matches(_T(":")))
{
if (m_LastToken.Matches(_T("public")))
m_LastScope = tsPublic;
else if (m_LastToken.Matches(_T("protected")))
m_LastScope = tsProtected;
else if (m_LastToken.Matches(_T("private")))
m_LastScope = tsPrivate;
m_Str.Clear();
}
else if (token.Matches(_T("while")) ||
token.Matches(_T("if")) ||
token.Matches(_T("do")) ||
token.Matches(_T("else")) ||
token.Matches(_T("for")) ||
token.Matches(_T("switch")))
{
if (!m_Options.useBuffer || m_Options.bufferSkipBlocks)
SkipToOneOfChars(_T(";}"), true);
else
m_Tokens.GetToken(); //skip args
m_Str.Clear();
}
else if (token.Matches(_T("typedef")) ||
token.Matches(_T("return")) ||
token.Matches(_T(":")))
{
SkipToOneOfChars(_T(";}"), true);
m_Str.Clear();
}
else if (token.Matches(_T("extern")))
{
// check for "C"
m_Str = m_Tokens.GetToken();
if (m_Str.Matches(_T("\"C\"")))
{
m_Tokens.GetToken(); // "eat" {
Parse(); // time for recursion ;)
}
else
SkipToOneOfChars(_T(";")); // skip externs
// m_Tokens.UngetToken(); // nope, return the token back...
m_Str.Clear();
}
else if (token.StartsWith(_T("__asm")))
{
SkipToOneOfChars(_T(";"), true);
//m_Str.Clear();
}
else if (token.Matches(_T("static")) ||
token.Matches(_T("virtual")) ||
token.Matches(_T("inline")))
{
// do nothing (skip it)
//m_Str.Clear();
}
else if (token.Matches(_T("#")))
{
token = m_Tokens.GetToken();
if (token.Matches(_T("include")))
HandleIncludes();
else if (token.Matches(_T("define")))
HandleDefines();
m_Str.Clear();
}
else if (token.Matches(_T("using"))) // using namespace ?
{
SkipToOneOfChars(_T(";}"), true);
m_Str.Clear();
}
else if (token.Matches(_T("namespace")))
{
m_Str.Clear();
HandleNamespace();
}
else if (token.Matches(_T("template")))
{
m_Str.Clear();
SkipToOneOfChars(_T(">;"), true);
}
else if (token.Matches(_T("class")))
{
m_Str.Clear();
HandleClass();
}
else if (token.Matches(_T("struct")))
{
m_Str.Clear();
HandleClass(false);
}
else if (token.Matches(_T("enum")))
{
m_Str.Clear();
HandleEnum();
}
else if (token.Matches(_T("union")))
{
SkipToOneOfChars(_T("{;"));
// if (m_Tokens.GetToken() == "{")
{
Token* oldparent = m_pLastParent;
Parse();
m_Str.Clear();
m_pLastParent = oldparent;
}
}
#if 1
else if (token.Matches(_T("operator")))
{
wxString func = token;
while (1)
{
token = m_Tokens.GetToken();
if (!token.IsEmpty())
{
if (token.GetChar(0) == '(')
{
// check for operator()()
wxString peek = m_Tokens.PeekToken();
if (!peek.IsEmpty() && peek.GetChar(0) != '(')
m_Tokens.UngetToken();
else
func << token;
break;
}
else
func << token;
}
else
break;
}
HandleFunction(func, true);
m_Str.Clear();
}
#endif
else
{
wxString peek = m_Tokens.PeekToken();
if (!peek.IsEmpty())
{
if (peek.GetChar(0) == '(' && !m_Options.useBuffer)
{
if (!m_Options.useBuffer || m_Options.bufferSkipBlocks)
{
// function
// ignore some well-known wxWindows macros
if (token.Matches(_T("BEGIN_EVENT_TABLE")))
{
// skip till after END_EVENT_TABLE
while (!token.IsEmpty() && !token.Matches(_T("END_EVENT_TABLE")))
token = m_Tokens.GetToken(); // skip args
m_Tokens.GetToken(); // skip args
}
else if (!token.Matches(_T("*_EVENT_TABLE*")) &&
!token.Matches(_T("IMPLEMENT_APP")) &&
!token.Matches(_T("IMPLEMENT_DYNAMIC_CLASS")) &&
!token.Matches(_T("WX_DECLARE_*")) &&
!token.Matches(_T("WX_DEFINE_*")))
{
// Log("m_Str='"+m_Str+"'");
// Log("token='"+token+"'");
// Log("peek='"+peek+"'");
HandleFunction(token);
}
else
m_Tokens.GetToken(); // skip args
}
else
m_Tokens.GetToken(); // eat args when parsing block
m_Str.Clear();
}
else if (peek.Matches(_T(",")))
{
// example decl to encounter a comma: int x,y,z;
// token should hold the var (x/y/z)
// m_Str should hold the type (int)
DoAddToken(tkVariable, token);
// skip comma (we had peeked it)
m_Tokens.GetToken();
}
else if (peek.Matches(_T("<")))
{
// a template, e.g. someclass<void>::memberfunc
// we have to skip <>, so we 're left with someclass::memberfunc
SkipAngleBraces();
peek = m_Tokens.PeekToken();
if (peek.Matches(_T("::")))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -