Code::Blocks  SVN r11506
parser_base.cpp
Go to the documentation of this file.
1 #include <sdk.h>
2 
3 #ifndef CB_PRECOMP
4  #include "editorbase.h"
5  #include <wx/dir.h>
6 #endif
7 
8 #include <wx/tokenzr.h>
9 #include <cbstyledtextctrl.h>
10 
11 #include "parser_base.h"
12 
13 
14 #define CC_PARSER_BASE_DEBUG_OUTPUT 0
15 
16 #if defined(CC_GLOBAL_DEBUG_OUTPUT)
17  #if CC_GLOBAL_DEBUG_OUTPUT == 1
18  #undef CC_PARSER_BASE_DEBUG_OUTPUT
19  #define CC_PARSER_BASE_DEBUG_OUTPUT 1
20  #elif CC_PARSER_BASE_DEBUG_OUTPUT == 2
21  #undef CC_PARSER_BASE_DEBUG_OUTPUT
22  #define CC_PARSER_BASE_DEBUG_OUTPUT 2
23  #endif
24 #endif
25 
26 #ifdef CC_PARSER_TEST
27  #define TRACE(format, args...) \
28  CCLogger::Get()->DebugLog(F(format, ##args))
29  #define TRACE2(format, args...) \
30  CCLogger::Get()->DebugLog(F(format, ##args))
31  #define TRACE2_SET_FLAG(traceFile)
32 
33  // don't use locker macros in the cctest project
34  #undef CC_LOCKER_TRACK_TT_MTX_LOCK
35  #define CC_LOCKER_TRACK_TT_MTX_LOCK(a)
36  #undef CC_LOCKER_TRACK_TT_MTX_UNLOCK
37  #define CC_LOCKER_TRACK_TT_MTX_UNLOCK(a)
38 #else
39  #if CC_PARSER_BASE_DEBUG_OUTPUT == 1
40  #define TRACE(format, args...) \
41  CCLogger::Get()->DebugLog(F(format, ##args))
42  #define TRACE2(format, args...)
43  #define TRACE2_SET_FLAG(traceFile)
44  #elif CC_PARSER_BASE_DEBUG_OUTPUT == 2
45  #define TRACE(format, args...) \
46  do \
47  { \
48  if (g_EnableDebugTrace) \
49  CCLogger::Get()->DebugLog(F(format, ##args)); \
50  } \
51  while (false)
52  #define TRACE2(format, args...) \
53  CCLogger::Get()->DebugLog(F(format, ##args))
54  #define TRACE2_SET_FLAG(traceFile) \
55  g_EnableDebugTrace = !g_DebugTraceFile.IsEmpty() && traceFile.EndsWith(g_DebugTraceFile)
56  #else
57  #define TRACE(format, args...)
58  #define TRACE2(format, args...)
59  #define TRACE2_SET_FLAG(traceFile)
60  #endif
61 #endif // CC_PARSER_TEST
62 
63 // both cctest and codecompletion plugin need the FileType() function, but the former is much
64 // simpler, so we use a preprocess directive here
65 #ifdef CC_PARSER_TEST
66 ParserCommon::EFileType ParserCommon::FileType(const wxString& filename, bool /*force_refresh*/)
67 {
68  static bool empty_ext = true;
69  static wxArrayString header_ext;
70  header_ext.Add(_T("h")); header_ext.Add(_T("hpp")); header_ext.Add(_T("tcc")); header_ext.Add(_T("xpm"));
71  static wxArrayString source_ext;
72  source_ext.Add(_T("c")); source_ext.Add(_T("cpp")); source_ext.Add(_T("cxx")); source_ext.Add(_T("cc")); source_ext.Add(_T("c++"));
73 
74  if (filename.IsEmpty())
75  {
76  wxString log;
77  log.Printf(wxT("ParserDummy::ParserCommon::FileType() : File '%s' is of type 'ftOther' (empty)."), filename.wx_str());
78  //CCLogger::Get()->Log(log);
79  return ParserCommon::ftOther;
80  }
81 
82  const wxString file = filename.AfterLast(wxFILE_SEP_PATH).Lower();
83  const int pos = file.Find(_T('.'), true);
84  wxString ext;
85  if (pos != wxNOT_FOUND)
86  ext = file.SubString(pos + 1, file.Len());
87 
88  if (empty_ext && ext.IsEmpty())
89  {
90  wxString log;
91  log.Printf(wxT("ParserDummy::ParserCommon::FileType() : File '%s' is of type 'ftHeader' (w/o ext.)."), filename.wx_str());
92  //CCLogger::Get()->Log(log);
94  }
95 
96  for (size_t i=0; i<header_ext.GetCount(); ++i)
97  {
98  if (ext==header_ext[i])
99  {
100  wxString log;
101  log.Printf(wxT("ParserDummy::ParserCommon::FileType() : File '%s' is of type 'ftHeader' (w/ ext.)."), filename.wx_str());
102  TRACE(log);
103  return ParserCommon::ftHeader;
104  }
105  }
106 
107  for (size_t i=0; i<source_ext.GetCount(); ++i)
108  {
109  if (ext==source_ext[i])
110  {
111  wxString log;
112  log.Printf(wxT("ParserDummy::ParserCommon::FileType() : File '%s' is of type 'ftSource' (w/ ext.)."), filename.wx_str());
113  TRACE(log);
114  return ParserCommon::ftSource;
115  }
116  }
117 
118  wxString log;
119  log.Printf(wxT("ParserDummy::ParserCommon::FileType() : File '%s' is of type 'ftOther' (unknown ext)."), filename.wx_str());
120  TRACE(log);
121 
122  return ParserCommon::ftOther;
123 }
124 #else
125 ParserCommon::EFileType ParserCommon::FileType(const wxString& filename, bool force_refresh)
126 {
127  static bool cfg_read = false;
128  static bool empty_ext = true;
129  static wxArrayString header_ext;
130  static wxArrayString source_ext;
131 
132  if (!cfg_read || force_refresh)
133  {
134  ConfigManager* cfg = Manager::Get()->GetConfigManager(_T("code_completion"));
135  empty_ext = cfg->ReadBool(_T("/empty_ext"), true);
136  wxString header_ext_str = cfg->Read(_T("/header_ext"), _T("h,hpp,hxx,hh,h++,tcc,tpp,xpm"));
137  wxString source_ext_str = cfg->Read(_T("/source_ext"), _T("c,cpp,cxx,cc,c++"));
138 
139  header_ext.Clear();
140  wxStringTokenizer header_ext_tknzr(header_ext_str, _T(","));
141  while (header_ext_tknzr.HasMoreTokens())
142  header_ext.Add(header_ext_tknzr.GetNextToken().Trim(false).Trim(true).Lower());
143 
144  source_ext.Clear();
145  wxStringTokenizer source_ext_tknzr(source_ext_str, _T(","));
146  while (source_ext_tknzr.HasMoreTokens())
147  source_ext.Add(source_ext_tknzr.GetNextToken().Trim(false).Trim(true).Lower());
148 
149  cfg_read = true; // caching done
150  }
151 
152  if (filename.IsEmpty())
153  return ParserCommon::ftOther;
154 
155  const wxString file = filename.AfterLast(wxFILE_SEP_PATH).Lower();
156  const int pos = file.Find(_T('.'), true);
157  wxString ext;
158  if (pos != wxNOT_FOUND)
159  ext = file.SubString(pos + 1, file.Len());
160 
161  if (empty_ext && ext.IsEmpty())
162  return ParserCommon::ftHeader;
163 
164  for (size_t i=0; i<header_ext.GetCount(); ++i)
165  {
166  if (ext==header_ext[i])
167  return ParserCommon::ftHeader;
168  }
169 
170  for (size_t i=0; i<source_ext.GetCount(); ++i)
171  {
172  if (ext==source_ext[i])
173  return ParserCommon::ftSource;
174  }
175 
176  return ParserCommon::ftOther;
177 }
178 #endif //CC_PARSER_TEST
179 
181 {
182  m_TokenTree = new TokenTree;
184 }
185 
187 {
189 
192 
194 }
195 
197 {
198  return m_TokenTree;
199 }
200 
201 bool ParserBase::ParseFile(const wxString& filename, bool isGlobal, bool /*locked*/)
202 {
203  return Reparse(filename, !isGlobal);
204 }
205 
206 bool ParserBase::Reparse(const wxString& file, cb_unused bool isLocal)
207 {
208  FileLoader* loader = new FileLoader(file);
209  (*loader)();
210 
211  ParserThreadOptions opts;
212 
213  opts.useBuffer = false; // default
214  opts.parentIdxOfBuffer = -1; // default
215  opts.initLineOfBuffer = -1; // default
216  opts.bufferSkipBlocks = false; // default
217  opts.bufferSkipOuterBlocks = false; // default
218  opts.isTemp = false; // default
219 
220  opts.followLocalIncludes = true; // default
221  opts.followGlobalIncludes = true; // default
222  opts.wantPreprocessor = true; // default
223  opts.parseComplexMacros = true; // default
224  opts.platformCheck = true; // default
225 
226  opts.handleFunctions = true; // default
227  opts.handleVars = true; // default
228  opts.handleClasses = true; // default
229  opts.handleEnums = true; // default
230  opts.handleTypedefs = true; // default
231 
232  opts.storeDocumentation = true; // enable this option to enable cctest for doxygen doc reading
233 
234  opts.loader = loader;
235 
236  // the file should first put in the TokenTree, so the index is correct when initializing the
237  // Tokenizer object inside the ParserThread::ParserThread()
238 
239  m_TokenTree->ReserveFileForParsing(file, true);
240 
241  ParserThread* pt = new ParserThread(this, file, true, opts, m_TokenTree);
242  bool success = pt->Parse();
243  delete pt;
244 
245  return success;
246 }
247 
248 
250  bool isLocal,
251  bool bufferSkipBlocks,
252  bool isTemp,
253  const wxString& filename,
254  int parentIdx,
255  int initLine)
256 {
257  ParserThreadOptions opts;
258 
259  opts.useBuffer = true;
260  opts.fileOfBuffer = filename;
261  opts.parentIdxOfBuffer = parentIdx;
262  opts.initLineOfBuffer = initLine;
263  opts.bufferSkipBlocks = bufferSkipBlocks;
264  opts.isTemp = isTemp;
265 
266  opts.followLocalIncludes = true;
267  opts.followGlobalIncludes = true;
269  opts.parseComplexMacros = true;
270  opts.platformCheck = true;
271 
272  opts.handleFunctions = true; // enabled to support function ptr in local block
273 
275 
276  ParserThread thread(this, buffer, isLocal, opts, m_TokenTree);
277 
278  bool success = thread.Parse();
279 
280  return success;
281 
282 }
283 
285 {
286  if (dir.IsEmpty())
287  return;
288 
289  wxString base = dir;
290  if (base.Last() == wxFILE_SEP_PATH)
291  base.RemoveLast();
292  if (!wxDir::Exists(base))
293  {
294  TRACE(_T("ParserBase::AddIncludeDir(): Directory %s does not exist?!"), base.wx_str());
295  return;
296  }
297 
298  if (m_IncludeDirs.Index(base) == wxNOT_FOUND)
299  {
300  TRACE(_T("ParserBase::AddIncludeDir(): Adding %s"), base.wx_str());
301  m_IncludeDirs.Add(base);
302  }
303 }
304 
306 {
307  wxString FirstFound = m_GlobalIncludes.GetItem(file);
308  if (FirstFound.IsEmpty())
309  {
310  wxArrayString FoundSet = FindFileInIncludeDirs(file,true);
311  if (FoundSet.GetCount())
312  {
313  FirstFound = UnixFilename(FoundSet[0]);
314  m_GlobalIncludes.AddItem(file, FirstFound);
315  }
316  }
317  return FirstFound;
318 }
319 
321 {
322  wxArrayString FoundSet;
323  for (size_t idxSearch = 0; idxSearch < m_IncludeDirs.GetCount(); ++idxSearch)
324  {
325  wxString base = m_IncludeDirs[idxSearch];
326  wxFileName tmp = file;
327  NormalizePath(tmp,base);
328  wxString fullname = tmp.GetFullPath();
329  if (wxFileExists(fullname))
330  {
331  FoundSet.Add(fullname);
332  if (firstonly)
333  break;
334  }
335  }
336 
337  TRACE(_T("ParserBase::FindFileInIncludeDirs(): Searching %s"), file.wx_str());
338  TRACE(_T("ParserBase::FindFileInIncludeDirs(): Found %lu"), static_cast<unsigned long>(FoundSet.GetCount()));
339 
340  return FoundSet;
341 }
342 
343 wxString ParserBase::GetFullFileName(const wxString& src, const wxString& tgt, bool isGlobal)
344 {
345  wxString fullname;
346  if (isGlobal)
347  {
348  fullname = FindFirstFileInIncludeDirs(tgt);
349  if (fullname.IsEmpty())
350  {
351  // not found; check this case:
352  //
353  // we had entered the previous file like this: #include <gl/gl.h>
354  // and it now does this: #include "glext.h"
355  // glext.h was correctly not found above but we can now search
356  // for gl/glext.h.
357  // if we still not find it, it's not there. A compilation error
358  // is imminent (well, almost - I guess the compiler knows a little better ;).
359  wxString base = wxFileName(src).GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
360  fullname = FindFirstFileInIncludeDirs(base + tgt);
361  }
362  }
363 
364  // NOTE: isGlobal is always true. The following code never executes...
365 
366  else // local files are more tricky, since they depend on two filenames
367  {
368  wxFileName fname(tgt);
369  wxFileName source(src);
370  if (NormalizePath(fname,source.GetPath(wxPATH_GET_VOLUME)))
371  {
372  fullname = fname.GetFullPath();
373  if (!wxFileExists(fullname))
374  fullname.Clear();
375  }
376  }
377 
378  return fullname;
379 }
380 
381 size_t ParserBase::FindTokensInFile(const wxString& filename, TokenIdxSet& result, short int kindMask)
382 {
383  result.clear();
384  size_t tokens_found = 0;
385 
386  TRACE(_T("Parser::FindTokensInFile() : Searching for file '%s' in tokens tree..."), filename.wx_str());
387 
389 
390  TokenIdxSet tmpresult;
391  if ( m_TokenTree->FindTokensInFile(filename, tmpresult, kindMask) )
392  {
393  for (TokenIdxSet::const_iterator it = tmpresult.begin(); it != tmpresult.end(); ++it)
394  {
395  const Token* token = m_TokenTree->at(*it);
396  if (token)
397  result.insert(*it);
398  }
399  tokens_found = result.size();
400  }
401 
403 
404  return tokens_found;
405 }
wxString AfterLast(wxUniChar ch) const
bool Parse()
Do the main job (syntax analysis) here.
wxMutex s_TokenTreeMutex
Definition: tokentree.cpp:49
wxString fileOfBuffer
which file the buffer belongs to, this usually happens when we parse a piece of the cbEditor and the ...
Definition: parserthread.h:76
A parser threaded task, which can be assigned to the thread task pool, and run there.
Definition: parserthread.h:138
virtual ~ParserBase()
bool followLocalIncludes
parse the file in #include "file" directive
Definition: parserthread.h:96
Token * at(int idx)
Definition: tokentree.h:51
void Delete(std::vector< T > &s)
Definition: safedelete.h:20
ConfigManager * GetConfigManager(const wxString &name_space) const
Definition: manager.cpp:474
static bool Exists(const wxString &dir)
static Manager * Get()
Use Manager::Get() to get a pointer to its instance Manager::Get() is guaranteed to never return an i...
Definition: manager.cpp:182
friend class ParserThread
Definition: parser_base.h:126
wxString Lower() const
bool platformCheck
not used
Definition: parserthread.h:108
bool isTemp
this value is passed to the generated Token&#39;s m_IsTemp property
Definition: parserthread.h:93
wxString FindFirstFileInIncludeDirs(const wxString &file)
ParserOptions m_Options
options for how the parser try to parse files
Definition: parser_base.h:196
bool wxFileExists(const wxString &filename)
bool ReadBool(const wxString &name, bool defaultVal=false)
int Index(const wxString &sz, bool bCase=true, bool bFromEnd=false) const
DLLIMPORT bool NormalizePath(wxFileName &f, const wxString &base)
Definition: globals.cpp:942
bool storeDocumentation
this will check for the platform of the project/target when adding include folders to the parser ...
Definition: parser_base.h:119
virtual bool ParseFile(const wxString &filename, bool isGlobal, bool locked=false)
a container class to hold all the Tokens getting from parsing stage
Definition: tokentree.h:37
int parentIdxOfBuffer
when parsing a function body, all the tokens are the children of the function token ...
Definition: parserthread.h:79
#define _T(string)
wxString GetNextToken()
wxArrayString FindFileInIncludeDirs(const wxString &file, bool firstonly=false)
it mimics what a compiler does to find an include header files, if the firstonly option is true...
#define wxT(string)
#define wxNOT_FOUND
EFileType FileType(const wxString &filename, bool force_refresh=false)
return a file type, which can be either header files or implementation files or other files ...
size_t AddItem(const wxString &s, T item, bool replaceexisting=false)
Adds an item to position defined by s and return the item number.
Definition: searchtree.h:474
virtual bool Reparse(cb_unused const wxString &filename, cb_unused bool isLocal=true)
DLLIMPORT wxString UnixFilename(const wxString &filename, wxPathFormat format=wxPATH_NATIVE)
Definition: globals.cpp:228
TokenTree * m_TempTokenTree
a temp Token tree hold some temporary tokens, e.g.
Definition: parser_base.h:193
a symbol found in the parsed files, it can be many kinds, such as a variable, a class and so on...
Definition: token.h:82
wxString & RemoveLast(size_t n=1)
std::set< int, std::less< int > > TokenIdxSet
Definition: token.h:16
#define TRACE(format, args...)
Definition: parser_base.cpp:57
size_t FindTokensInFile(const wxString &filename, TokenIdxSet &result, short int kindMask)
EFileType
the enum type of the file type
Definition: parser_base.h:25
bool handleFunctions
whether to parse the functions
Definition: parserthread.h:111
size_t FindTokensInFile(const wxString &filename, TokenIdxSet &result, short int kindMask)
find tokens belong to a specified file
Definition: tokentree.cpp:298
TokenTree * m_TokenTree
each Parser class contains a TokenTree object which used to record tokens per project this tree will ...
Definition: parser_base.h:187
wxString Read(const wxString &key, const wxString &defaultVal=wxEmptyString)
bool wantPreprocessor
case sensitive in MarkItemsByAI
Definition: parser_base.h:114
bool wantPreprocessor
handle the #if like preprocessor directives, this value is passed to Tokenizer
Definition: parserthread.h:102
#define CC_LOCKER_TRACK_TT_MTX_UNLOCK(M)
Definition: cclogger.h:165
const wxStringCharType * wx_str() const
void AddIncludeDir(const wxString &dir)
add a directory to the Parser&#39;s include path database
bool parseComplexMacros
not used
Definition: parserthread.h:105
wxString & Trim(bool fromRight=true)
bool storeDocumentation
should tokenizer detect and store doxygen documentation?
Definition: parserthread.h:126
wxArrayString m_IncludeDirs
the include directories can be either three kinds below: 1, compiler&#39;s default search paths...
Definition: parser_base.h:212
#define CC_LOCKER_TRACK_TT_MTX_LOCK(M)
Definition: cclogger.h:159
bool HasMoreTokens() const
bool IsEmpty() const
void Clear()
wxString GetPath(int flags=wxPATH_GET_VOLUME, wxPathFormat format=wxPATH_NATIVE) const
size_t Len() const
bool useBuffer
useBuffer specifies that we&#39;re not parsing a file, but a temporary buffer.
Definition: parserthread.h:71
size_t Add(const wxString &str, size_t copies=1)
T GetItem(const wxString &s)
Gets the item at position defined by key string s.
Definition: searchtree.h:466
size_t GetCount() const
int Find(wxUniChar ch, bool fromEnd=false) const
virtual TokenTree * GetTokenTree() const
wxUniChar Last() const
bool followGlobalIncludes
parse the file in #include <file> directive
Definition: parserthread.h:99
size_t ReserveFileForParsing(const wxString &filename, bool preliminary=false)
mark a file to be parsed.
Definition: tokentree.cpp:896
wxString SubString(size_t from, size_t to) const
int initLineOfBuffer
since we are not parsing start from the first line of the file, this is the first line number of the ...
Definition: parserthread.h:84
int Printf(const wxString &pszFormat,...)
SearchTree< wxString > m_GlobalIncludes
wxString -> wxString map
Definition: parser_base.h:205
wxString GetFullPath(wxPathFormat format=wxPATH_NATIVE) const
bool bufferSkipBlocks
do we parse inside the {...} body
Definition: parserthread.h:87
virtual bool ParseBuffer(const wxString &buffer, bool isLocal, bool bufferSkipBlocks=false, bool isTemp=false, const wxString &filename=wxEmptyString, int parentIdx=-1, int initLine=0)
wxString GetFullFileName(const wxString &src, const wxString &tgt, bool isGlobal)