📄 parser.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: parser.cpp,v 1.25.2.1 2005/10/25 07:59:01 mandrav Exp $
* $Date: 2005/10/25 07:59:01 $
*/
#include <sdk.h>
#include <wx/log.h>
#include <wx/app.h>
#include <wx/filename.h>
#include <wx/tokenzr.h>
#include <wx/intl.h>
#include <wx/progdlg.h>
#include "parser.h"
#ifndef STANDALONE
#include <configmanager.h>
#include <messagemanager.h>
#include <manager.h>
#include <globals.h>
#endif // STANDALONE
static const char CACHE_MAGIC[] = "CCCACHE_1_0";
static char CACHE_MAGIC_READ[] = " ";
static wxMutex s_mutexListProtection;
int PARSER_END = wxNewId();
static int idPool = wxNewId();
BEGIN_EVENT_TABLE(Parser, wxEvtHandler)
// EVT_MENU(NEW_TOKEN, Parser::OnNewToken)
// EVT_MENU(FILE_NEEDS_PARSING, Parser::OnParseFile)
EVT_THREADTASK_STARTED(idPool, Parser::OnStartThread)
EVT_THREADTASK_ENDED(idPool, Parser::OnEndThread)
EVT_THREADTASK_ALLDONE(idPool, Parser::OnAllThreadsDone)
END_EVENT_TABLE()
Parser::Parser(wxEvtHandler* parent)
: m_MaxThreadsCount(8),
m_pParent(parent)
#ifndef STANDALONE
,m_pImageList(0L)
#endif
,m_abort_flag(false),
m_UsingCache(false),
m_CacheFilesCount(0),
m_CacheTokensCount(0),
m_Pool(this, idPool)
{
ReadOptions();
#ifndef STANDALONE
m_pImageList = new wxImageList(16, 16);
wxBitmap bmp;
wxString prefix;
prefix = ConfigManager::Get()->Read(_T("data_path")) + _T("/images/codecompletion/");
// bitmaps must be added by order of PARSER_IMG_* consts
bmp.LoadFile(prefix + _T("class_folder.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_CLASS_FOLDER
bmp.LoadFile(prefix + _T("class.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_CLASS
bmp.LoadFile(prefix + _T("ctor_private.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_CTOR_PRIVATE
bmp.LoadFile(prefix + _T("ctor_protected.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_CTOR_PROTECTED
bmp.LoadFile(prefix + _T("ctor_public.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_CTOR_PUBLIC
bmp.LoadFile(prefix + _T("dtor_private.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_DTOR_PRIVATE
bmp.LoadFile(prefix + _T("dtor_protected.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_DTOR_PROTECTED
bmp.LoadFile(prefix + _T("dtor_public.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_DTOR_PUBLIC
bmp.LoadFile(prefix + _T("method_private.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_FUNC_PRIVATE
bmp.LoadFile(prefix + _T("method_protected.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_FUNC_PRIVATE
bmp.LoadFile(prefix + _T("method_public.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_FUNC_PUBLIC
bmp.LoadFile(prefix + _T("var_private.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_VAR_PRIVATE
bmp.LoadFile(prefix + _T("var_protected.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_VAR_PROTECTED
bmp.LoadFile(prefix + _T("var_public.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_VAR_PUBLIC
bmp.LoadFile(prefix + _T("preproc.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_PREPROCESSOR
bmp.LoadFile(prefix + _T("enum.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_ENUM
bmp.LoadFile(prefix + _T("enumerator.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_ENUMERATOR
bmp.LoadFile(prefix + _T("namespace.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_NAMESPACE
bmp.LoadFile(prefix + _T("symbols_folder.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_SYMBOLS_FOLDER
bmp.LoadFile(prefix + _T("enums_folder.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_ENUMS_FOLDER
bmp.LoadFile(prefix + _T("preproc_folder.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_PREPROC_FOLDER
bmp.LoadFile(prefix + _T("others_folder.png"), wxBITMAP_TYPE_PNG);
m_pImageList->Add(bmp); // PARSER_IMG_OTHERS_FOLDER
#endif // STANDALONE
ConnectEvents();
}
Parser::~Parser()
{
DisconnectEvents();
Clear();
#ifndef STANDALONE
delete m_pImageList;
#endif // STANDALONE
}
void Parser::ConnectEvents()
{
// Connect(EVT_THREADTASK_STARTED, -1, cbEVT_THREADTASK_STARTED,
// (wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction)
// &Parser::OnStartThread);
// Connect(EVT_THREADTASK_ENDED, -1, cbEVT_THREADTASK_ENDED,
// (wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction)
// &Parser::OnEndThread);
Connect(NEW_TOKEN, -1, wxEVT_COMMAND_MENU_SELECTED,
(wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction)
&Parser::OnNewToken);
Connect(FILE_NEEDS_PARSING, -1, wxEVT_COMMAND_MENU_SELECTED,
(wxObjectEventFunction)(wxEventFunction)(wxCommandEventFunction)
&Parser::OnParseFile);
}
void Parser::DisconnectEvents()
{
// Disconnect(EVT_THREADTASK_STARTED, -1, cbEVT_THREADTASK_STARTED);//,
// Disconnect(EVT_THREADTASK_ENDED, -1, cbEVT_THREADTASK_ENDED);//,
Disconnect(NEW_TOKEN, -1, wxEVT_COMMAND_MENU_SELECTED);//,
Disconnect(FILE_NEEDS_PARSING, -1, wxEVT_COMMAND_MENU_SELECTED);//,
}
void Parser::ReadOptions()
{
#ifdef STANDALONE
m_Options.followLocalIncludes = true;
m_Options.followGlobalIncludes = false;
m_Options.caseSensitive = true;
m_Options.wantPreprocessor = false;
m_Options.useSmartSense = true;
m_BrowserOptions.showInheritance = false;
m_BrowserOptions.viewFlat = false;
#else // !STANDALONE
m_MaxThreadsCount = ConfigManager::Get()->Read(_T("/code_completion/max_threads"), 8);
m_Options.followLocalIncludes = ConfigManager::Get()->Read(_T("/code_completion/parser_follow_local_includes"), 1L);
m_Options.followGlobalIncludes = ConfigManager::Get()->Read(_T("/code_completion/parser_follow_global_includes"), 0L);
m_Options.caseSensitive = ConfigManager::Get()->Read(_T("/code_completion/case_sensitive"), 0L);
m_Options.useSmartSense = ConfigManager::Get()->Read(_T("/code_completion/use_SmartSense"), 1);
m_Options.wantPreprocessor = ConfigManager::Get()->Read(_T("/code_completion/want_preprocessor"), 0L);
m_BrowserOptions.showInheritance = ConfigManager::Get()->Read(_T("/code_completion/browser_show_inheritance"), 0L);
m_BrowserOptions.viewFlat = ConfigManager::Get()->Read(_T("/code_completion/browser_view_flat"), 0L);
#endif // STANDALONE
}
void Parser::WriteOptions()
{
#ifndef STANDALONE
ConfigManager::Get()->Write(_T("/code_completion/max_threads"), (int)m_MaxThreadsCount);
ConfigManager::Get()->Write(_T("/code_completion/parser_follow_local_includes"), m_Options.followLocalIncludes);
ConfigManager::Get()->Write(_T("/code_completion/parser_follow_global_includes"), m_Options.followGlobalIncludes);
ConfigManager::Get()->Write(_T("/code_completion/case_sensitive"), m_Options.caseSensitive);
ConfigManager::Get()->Write(_T("/code_completion/use_SmartSense"), m_Options.useSmartSense);
ConfigManager::Get()->Write(_T("/code_completion/want_preprocessor"), m_Options.wantPreprocessor);
ConfigManager::Get()->Write(_T("/code_completion/browser_show_inheritance"), m_BrowserOptions.showInheritance);
ConfigManager::Get()->Write(_T("/code_completion/browser_view_flat"), m_BrowserOptions.viewFlat);
#endif // STANDALONE
}
bool Parser::CacheNeedsUpdate()
{
if (m_UsingCache)
{
ClearTemporaries(); // no temps in counting
if (m_CacheFilesCount == (int)m_ParsedFiles.GetCount() &&
m_CacheTokensCount == (int)m_Tokens.GetCount())
{
// in-mem data and cache seem to be in sync
// @warning: this is *not* bulletproof!
// consider a token name change, for example...
// maybe use a CRC of some kind?
return false;
}
}
return true;
}
bool Parser::ReadFromCache(wxFile* f)
{
// File format is like this:
//
// CACHE_MAGIC
// Number of parsed files
// Number of tokens
// Parsed files
// Tokens
// EOF
// keep a backup of include dirs
wxArrayString dirs = m_IncludeDirs;
Manager::Get()->GetMessageManager()->DebugLog(_("Clearing Cache"));
Clear();
// restore backup
m_IncludeDirs = dirs;
Manager::Get()->GetMessageManager()->DebugLog(_("Begin reading..."));
if (f->Read(CACHE_MAGIC_READ, sizeof(CACHE_MAGIC_READ)) != sizeof(CACHE_MAGIC_READ) ||
strncmp(CACHE_MAGIC, CACHE_MAGIC_READ, sizeof(CACHE_MAGIC_READ) != 0))
{
return false;
}
int fcount = 0;
int tcount = 0;
Manager::Get()->GetMessageManager()->DebugLog(_("Reading fcount..."));
if (!LoadIntFromFile(f, &fcount)) return false;
Manager::Get()->GetMessageManager()->DebugLog(_("Reading tcount..."));
if (!LoadIntFromFile(f, &tcount)) return false;
wxProgressDialog* progress = 0;
unsigned int counter = 0;
// display cache progress?
if (ConfigManager::Get()->Read(_T("/code_completion/show_cache_progress"), 1L))
{
Manager::Get()->GetMessageManager()->DebugLog(_("Creating progress dialog..."));
progress = new wxProgressDialog(_("Code-completion plugin"),
_("Please wait while loading code-completion cache..."),
fcount + tcount);
}
// m_ParsedFiles
Manager::Get()->GetMessageManager()->DebugLog(_("Reading data from cache NOW"));
wxString file;
for (int i = 0; i < fcount && !f->Eof(); ++i)
{
if (!LoadStringFromFile(f, file))
{
delete progress;
return false;
}
m_ParsedFiles.Add(file);
if (progress)
progress->Update(++counter);
}
Manager::Get()->GetMessageManager()->DebugLog(_("Calculating tokens..."));
// m_Tokens
for (int i = 0; i < tcount && !f->Eof(); ++i)
{
// update m_Int for inheritance to be serialized properly
Token* token = new Token;
token->m_Int = i;
m_Tokens.Add(token);
}
for (int i = 0; i < tcount && !f->Eof(); ++i)
{
Token* token = m_Tokens[i];
if (!token->SerializeIn(f))
{
delete progress;
return false;
}
if (progress)
progress->Update(++counter);
}
Manager::Get()->GetMessageManager()->DebugLog(_("Updating linking pointers..."));
// now we must update linking pointers in tokens
for (int i = 0; i < tcount; ++i)
{
Token* token = m_Tokens[i];
token->m_pParent = token->m_ParentIndex != -1 ? m_Tokens[token->m_ParentIndex] : 0;
// sanity check
if (token->m_pParent == token)
token->m_pParent = 0;
for (unsigned int j = 0; j < token->m_AncestorsIndices.GetCount(); ++j)
{
if (token->m_AncestorsIndices[j] != -1)
{
Token* ancestor = m_Tokens[token->m_AncestorsIndices[j]];
if (ancestor != token) // sanity check
token->m_Ancestors.Add(ancestor);
}
}
for (unsigned int j = 0; j < token->m_ChildrenIndices.GetCount(); ++j)
{
if (token->m_ChildrenIndices[j] != -1)
{
Token* child = m_Tokens[token->m_ChildrenIndices[j]];
if (child != token) // sanity check
token->m_Children.Add(child);
}
}
}
// LinkInheritance(); // fix ancestors relationships
Manager::Get()->GetMessageManager()->DebugLog(_("Cleaning up subroutine..."));
m_UsingCache = true;
m_CacheFilesCount = m_ParsedFiles.GetCount();
m_CacheTokensCount = m_Tokens.GetCount();
Manager::Get()->GetMessageManager()->DebugLog(_("Deleting progress dialog (if any)..."));
if (progress)
delete progress;
Manager::Get()->GetMessageManager()->DebugLog(_("Finished reading from cache."));
return true;
}
bool Parser::WriteToCache(wxFile* f)
{
// File format is like this:
//
// CACHE_MAGIC
// Number of parsed files
// Number of tokens
// Parsed files
// Tokens
// EOF
ClearTemporaries(); // no temps in cache
unsigned int tcount = m_Tokens.GetCount();
unsigned int fcount = m_ParsedFiles.GetCount();
unsigned int counter = 0;
wxProgressDialog* progress = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -